ThreadPoolExecutor类

本文详细介绍了线程池的创建方式、线程管理和任务队列等核心概念。探讨了线程池的不同创建方法及其内部实现原理,分析了不同类型的队列特点及适用场景,并讨论了如何合理设置线程数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

线程的创建

两种方式,一种是new一个ThreadPoolExecutor

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) 

参数说明省略

另一种方式,使用Executors类中提供的几个静态工厂方法来创建线程池:

//来任务就创建线程,当线程空闲超过60秒,销毁线程。 里面调用 ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>())
Executors.newCachedThreadPool(); 
​
//创建容量为1的缓冲池,里面调用 ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>())
Executors.newSingleThreadExecutor();   
​
//创建固定容量大小的缓冲池,里面调用 ThreadPoolExecutor(int, int, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
Executors.newFixedThreadPool(int); 

但是!!!阿里巴巴Java开发手册中指出
在这里插入图片描述

提交任务的两种方式

  • Callable
    该类任务有返回结果,可以抛出异常。
    通过submit函数提交,返回Future对象。
    可通过get获取执行结果。
  • Runnable
    该类任务只执行,无法获取返回结果,并在执行过程中无法抛异常。
    通过execute提交。

区别:submit方法内部本质上还是调用的execute方法,submit方法能用Future获取调用的返回结果。

线程的中断

shutdown():将线程池的状态设置成SHUTDOWN状态,然后中断所有没有正在执行任务的线程。

shutdownNow():遍历线程池中的工作线程,然后逐个调用线程的interrupt方法来中断线程,所以无法响应中断的任务可能永远无法终止。

线程的销毁

受制于keepAliveTime。当线程不再被使用时,不会自动关闭。因此为了确保线程关闭,通过设置合理的keep-alive times,设置核心线程(core threads)数目为0或设置allowCoreThreadTimeOut(boolean)。只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用。但是如果调用了allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0

任务队列

//无界队列,由链表实现,当线程数超过corePoolSize时,采用该队列则不会再创建线程。此时maximumPoolSize的时不会起作用。
//如果任务处理速度小于任务到达速度,采用这种队列的话,队列的长度会越来越长
LinkedBlockingQueue
​
//有界队列,由数组实现,需要考虑队列大小和最大线程池数量之间的折中。使用较长的队列和较少的最大线程池数量,会减少CPU使用、系统资源和上下文切换开销,但是吞吐量低。
//相反,使用较短的队列通常需要较大的最大线程池数量,会使CPU更忙碌但是调度开销大,也会使吞吐量降低。
ArrayBlockingQueue
​
//同步阻塞队列,该队列不储存元素。
//每个插入操作必须等到另一个线程调用移除操作
SynchronousQueue
​
//有界队列,优先级阻塞队列
PriorityBlockingQueue
​
队列吞吐量比较:
SynchronousQueue > LinkedBlockingQueue > ArrayBlockingQueue

饱和策略

当实际线程数超过最大线程数,并且阻塞队列已满时,就会调用饱和策略。

  • ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
  • ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
  • ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
  • ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务

线程数量设置

  • CPU密集型任务
    尽量使用较小的线程池,一般为CPU核心数+1。
    因为CPU密集型任务使得CPU使用率很高,若开过多的线程数,只能增加上下文切换的次数,因此会带来额外的开销。

  • IO密集型任务
    可以使用稍大的线程池,一般为2*CPU核心数。
    IO密集型任务CPU使用率并不高,因此可以让CPU在等待IO的时候去处理别的任务,充分利用CPU时间。

  • 最佳线程数目 = (线程等待时间与线程CPU时间之比 + 1)* CPU数目 http://ifeve.com/how-to-calculate-threadpool-size/

参考:
https://www.cnblogs.com/my376908915/p/6761364.html
https://zhuanlan.zhihu.com/p/33264000
https://zhuanlan.zhihu.com/p/32867181

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值