展开
拓展 关闭
订阅号推广码
GitHub
视频
公告栏 关闭

线程池

  • 简介
1、诸如 Web 服务器、数据库服务器、文件服务器或邮件服务器之类的许多服务器应用程序都面向处理来自某些远程来源的大量短小的任务。请求以某种方式到达服务器,这种方式可能是通过网络协议(例如 HTTP、FTP )、通过 JMS队列或者可能通过轮询数据库。不管请求如何到达,服务器应用程序中经常出现的情况是:单个任务处理的时间很短而请求的数目却是巨大的。每当一个请求到达就创建一个新线程,然后在新线程中为请求服务,但是频繁的创建线程,销毁线程所带来的系统开销其实是非常大的
2、线程池为线程生命周期开销问题和资源不足问题提供了解决方案。通过对多个任务重用线程,线程创建的开销被分摊到了多个任务上。其好处是,因为在请求到达时线程已经存在,所以无意中也消除了线程创建所带来的延迟。这样,就可以立即为请求服务,使应用程序响应更快。而且,通过适当地调整线程池中的线程数目,也就是当请求的数目超过某个阈值时,就强制其它任何新到的请求一直等待,直到获得一个线程来处理为止,从而可以防止资源不足
3、风险与机遇:用线程池构建的应用程序容易遭受任何其它多线程应用程序容易遭受的所有并发风险,诸如同步错误和死锁,它还容易遭受特定于线程池的少数其它风险,诸如与池有关的死锁、资源不足和线程泄漏
  • 案例1
public class ThreadPoolDemo {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 创建队列,队列大小指定20
        LinkedBlockingQueue<Runnable> objects = new LinkedBlockingQueue<>(10);
        // 创建线程池,每次处理10个任务,3秒
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 20, 3L,
                TimeUnit.SECONDS, objects);
        Future<String> submit = null;
        for (int i = 0; i < 100; i++) {
            threadPoolExecutor.submit(()->{         // 提交任务
                try {
                    Thread.sleep(2000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName());
            });
        }
    }

}

# 控制台打印结果:
pool-1-thread-10
pool-1-thread-18
pool-1-thread-7
pool-1-thread-3
pool-1-thread-8
pool-1-thread-9
pool-1-thread-2
pool-1-thread-13
pool-1-thread-20
pool-1-thread-14
  • Future、Callable、FutureTask
1、Callable与Runable功能相似,Callable的call有返回值,可以返回给客户端,而Runable没有返回值,一般情况下,Callable与FutureTask一起使用,或者通过线程池的submit方法返回相应的Future
2、Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果、设置结果操作。get方法会阻塞,直到任务返回结果
3、FutureTask则是一个RunnableFuture,而RunnableFuture实现了Runnbale又实现了Futrue这两个接口
  • 案例2
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class CallableDemo implements Callable<String> {

    // 重写该方法,返回数据
    @Override
    public String call() throws Exception {
        Thread.sleep(3000L);
        return "1111";
    }

    // 测试
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // new 1个callable实现的队列
        CallableDemo callableDemo = new CallableDemo();
        // 将该对象作为参数传入
        FutureTask<String> stringFutureTask = new FutureTask<>(callableDemo);
        // 将stringFutureTask作为参数传入线程
        new Thread(stringFutureTask).start();
        // 获取到返回结果
        System.out.println(stringFutureTask.get());
    }

}
  • 案例3:线程池中使用Callable
public class ThreadPoolDemo {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 创建队列,容量大小指定为无限制
        LinkedBlockingQueue<Runnable> objects = new LinkedBlockingQueue<>();

        // 创建线程池,每次处理10个任务,3秒
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 20, 3L,
                TimeUnit.SECONDS, objects);

        Future<String> submit = null;

        for (int i = 0; i < 100; i++) {
            submit = threadPoolExecutor.submit(new CallableDemo());
        }

        for (int i = 0; i < 100; i++) {
            System.out.println(submit.get());
        }
    }

}
posted @ 2022-05-16 15:34  DogLeftover  阅读(36)  评论(0编辑  收藏  举报