线程池ThreadPoolExecutor详解以及多种线程池的实现

1、线程池状态含义

        ThreadPoolExecutor 使用 int 的高 3 位来表示线程池状态,低 29 位表示线程数量,之所以将信息存储在一个变量中,是为了保证原子性。
        具体的高三位与线程池状态如下,引用自网课的图片:

 2、构造方法的参数、具体工作方式

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

对于以上变量,其含义如下:
corePoolSize 核心线程数目 (最多保留的线程数)

maximumPoolSize 最大线程数目

keepAliveTime 生存时间

unit 生存时间的时间单位

workQueue 阻塞队列

threadFactory 线程工厂 - 可以为线程创建时起个好名字

handler 拒绝策略

具体解释:
        1.核心线程数:是指在线程池中始终保持存活的线程数量。在线程池中,当有新的任务到达时,线程池会创建新的线程来处理任务,但是当任务处理完毕后,线程并不会立即销毁,而是被放置在线程池中等待下一个任务的到来。
        当将 allowCoreThreadTimeout 设置为 true 时,核心线程也会超时回收,像这样:

executor.allowCoreThreadTimeOut(true); // 允许回收核心线程

        2.最大线程数目:指核心线程数+非核心线程数的总数。例如设置核心为5,最大为10,那么非核心(救急)则为10-5=5个

        3.生存时间:线程闲置超时时长。如果超过该时长,非核心线程就会被回收。如果将 allowCoreThreadTimeout 设置为 true 时,核心线程也会超时回收。

        4.阻塞队列:如果核心线程都被占用没有空闲,此时又多来了新任务,则新来的任务会被加入阻塞队列阻塞等待。

        5.拒绝策略:如果阻塞队列满了,继续来任务,那么就创建救急线程来执行新任务,但如果救急线程也不够(达到最大线程数),再来任务,因为线程池已经填满了到极限了,所以就要拒绝新来的任务了。jdk和各种框架有多种拒绝策略的实现:

  • AbortPolicy 让调用者抛出 RejectedExecutionException 异常,这是默认策略
  • CallerRunsPolicy 让调用者运行任务
  • DiscardPolicy 放弃本次任务
  • DiscardOldestPolicy 放弃队列中最早的任务,本任务取而代之
  • ActiveMQ 的实现,带超时等待(60s)尝试放入队列(较好)

3、 线程池有哪些常用的实现方式

3.1 newFixedThreadPool(全是、多个核心线程不回收)

        fixed,即“固定的”,线程数固定,能够控制线程的最大并发数:
        (1)源码中,其核心线程数和最大线程数都是nThreads,即相等,说明没有非核心线程
        (2)阻塞队列是无界的,可以放任意数量的任务。
        (3)核心线程不会自动回收,直到被明确打断:“The threads in the pool will exist until it is explicitly shutdown.”

public static ExecutorService newFixedThreadPool(int nThreads) {
     return new ThreadPoolExecutor(nThreads, nThreads,
     0L, TimeUnit.MILLISECONDS,
     new LinkedBlockingQueue<Runnable>());
}
//具体使用示例
//1.创建定长线程池对象,线程数量固定为3
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
//2. 创建Runnable线程对象以及执行的任务
Runnable task =new Runnable(){
  public void run() {
     System.out.println("执行任务啦");
  }
};
//3. 向线程池提交任务
fixedThreadPool.execute(task);

3.2 newCachedThreadPool(全是非核心,定时回收)

        Cached,缓存,是说这种线程池的实现像缓存一样是可变的:
        (1)核心线程数是 0, 最大线程数是 Integer.MAX_VALUE,线程的空闲生存时间是 60s,意味着:这种线程池内都是非核心线程、可以无限创建、定时60s回收。
       
(2)队列采用了 SynchronousQueue ,特点是,它没有容量,没有线程来取是放不进去的。
        (3)适合场景:执行大量、耗时少的任务。

public static ExecutorService newCachedThreadPool() {
     return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
     60L, TimeUnit.SECONDS,
     new SynchronousQueue<Runnable>());
}

3.3 newSingleThreadExecutor(就一个核心线程,不回收)

        Single,即单线程的线程池:只有 1 个核心线程,无非核心线程,执行后不会立即回收。
        这样相当于顺序执行,不需要处理线程同步问题。

public static ExecutorService newSingleThreadExecutor() {
 return new FinalizableDelegatedExecutorService
     (new ThreadPoolExecutor(1, 1,
         0L, TimeUnit.MILLISECONDS,
         new LinkedBlockingQueue<Runnable>()));
}

3.4 newScheduledThreadPool(核心非核心都有,非核心定时回收)

        Scheduled即定时的:核心线程数量固定,非核心线程数量无限多但会定时回收,当非核心线程执行完闲置 10ms 后则回收,任务队列为延时阻塞队列。
        应用场景:执行定时或周期性的任务。

private static final long DEFAULT_KEEPALIVE_MILLIS = 10L;

        

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

好奇的7号

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值