ThreadPoolExecutor如何创建线程池

Posted llllitm

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ThreadPoolExecutor如何创建线程池相关的知识,希望对你有一定的参考价值。

一、为什么要使用线程池?

a)      减少开销。因为创建和销毁线程需要和底层操作系统交互,每个线程都去做这个操作,会浪费大量的时间,降低系统效率

b)      避免内存溢出。线程池的线程数量不会超过最大值,不使用线程池可能会造成无限制的创建线程

二、为什么不使用Executors来创建线程池

a)      Java中有自带的线程池工具Executors,但是阿里巴巴的JAVA开发手册中指明不要使用,原因如图所示。

技术图片
其中原因是线程池的缓冲队列为BlockingQueue,其实现有ArrayBlockingQueue和LinkedBlockingQueue两种。当使用数组队列的时候必须指定容量,但是使用链表的队列则可以不用指明容量,将会行成一个最大容量为Integer.Max_Value的队列,而使用Executors的时候是没有指定链表长度的,因此可能会造成内存溢出。并且其中许多方法已经将参数定义好了,不能够灵活调整。因此,推荐使用ThreadPoolExecutor。

 

三、ThreadPoolExecutor如何创建

a)      我使用的构造方法是public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler)

corePoolSize:核心线程数,这些线程即便是在空闲的时候,也不会被关闭。

maximumPoolSize:最大线程数,当缓冲队列被装满的时候,就会开始创建新的线程,线程池中的线程数量不会超过这个值,新创建出来的线程在空闲的时候会被回收。

keepAliveTime:非核心空闲线程的存活时间。

Unit:存活时间单位。

workQueue:缓冲队列,当线程已经被全部使用,请求就会放在缓冲队列中,等待处理,其实现类为ArrayBlockingQueue和LinkedBlockingQueue,建议设置长度才不会造成内存溢出。

threadFactory:创建线程的方法,可以在里面对新建的线程做一个自定义操作。

RejectedExecutionHandler:当缓冲队列满了后,对新来的请求进行处理。可以抛弃、返回请求、重新添加到队列等操作,亦可以使用默认的策略:

    1. AbortPolicy:抛出异常。
    2. DiscardPolicy:直接抛弃请求。
    3. DiscardOldestPolicy:丢弃队列中最老的任务。
    4. CallerRunsPolicy:将任务分配给当前执行execute方法线程来处理。

这些参数中maximumPoolSize >= corePoolSize >0有这样的关系。

四、查看运行期间线程池的状态

ThreadPoolExecutor.getQueue().size():当前排队线程数

ThreadPoolExecutor.getActiveCount():当前活动线程数

ThreadPoolExecutor.getCompletedTaskCount():执行完成线程数

ThreadPoolExecutor.getTaskCount:总线程数

五、如何关闭线程池

a)      ShutDownNow

线程池拒绝新的任务,并且关闭所有线程、线程池

b)      ShutDown

线程池拒绝新的任务,但是会等待线程池所有的任务结束后再关闭线程池

       参考https://www.cnblogs.com/qingquanzi/p/9018627.html

       在最后调用一次ThreadPoolExecutor.isTerminated()方法,该方法确保等待子线程运行完成后再退出主线程。

六、参考代码

  获取线程池的方法

 1 public static ThreadPoolExecutor getInstence(){
 2         if (threadPool == null){
 3             synchronized (ThreadPoolExecutor.class){
 4                 if (threadPool == null){
 5                     threadPool = new ThreadPoolExecutor(
 6                             5,
 7                             10,
 8                             60,
 9                             TimeUnit.SECONDS,
10                             new ArrayBlockingQueue<>(100, true),
11                             r -> {
12                                 Thread thread = new Thread(r);
13                                 thread.setName("thread_Test");
14                                 return thread;
15                             },
16                             (r, executor) -> {
17                                 BlockingQueue<Runnable> queue = executor.getQueue();
18                                 try {
19                                     queue.put(r);
20                                 } catch (InterruptedException e) {
21                                     e.printStackTrace();
22                                 }
23                             }
24                     );
25                 }
26             }
27         }
28         return threadPool;
29     }
 1 public static void main(String[] args) {
 2         ThreadPoolExecutor threadPool = ThreadPoolUtils.getInstence();
 3         for (int i = 0; i < 1000; i++) {
 4             System.out.println("当前执行任务:::Task"+i);
 5             threadPool.execute(() -> {
 6                 try {
 7                     Thread.sleep(1000);
 8                 } catch (InterruptedException e) {
 9                     e.printStackTrace();
10                 }
11             });
12         }
13         threadPool.shutdown();
14         while (!threadPool.isTerminated()){
15             System.out.println("当前排队线程数====="+threadPool.getQueue().size());
16             System.out.println("当前活动线程数====="+threadPool.getActiveCount());
17             System.out.println("当前完成线程数====="+threadPool.getCompletedTaskCount());
18             System.out.println("总线程数==========="+threadPool.getTaskCount());
19             try {
20                 Thread.sleep(3000);
21             } catch (InterruptedException e) {
22                 e.printStackTrace();
23             }
24         }
25     }

 

以上是关于ThreadPoolExecutor如何创建线程池的主要内容,如果未能解决你的问题,请参考以下文章

如何优雅的自定义 ThreadPoolExecutor 线程池

如何优雅的自定义 ThreadPoolExecutor 线程池

如何优雅的自定义 ThreadPoolExecutor 线程池

线程池那些事之ThreadPoolExecutor

创建线程池的核心方式 --- ThreadPoolExecutor

手撕ThreadPoolExecutor线程池源码