Java ThreadPoolExecutor 的介绍及使用

目录

ThreadPoolExecutor

        1) 线程池状态

        2) 构造方法

        3) 固定数量线程池 FixedThreadPool

        4) 带缓冲线程池 CacheThreadPool

        5) 单线程线程池 SingleThreadExecutor

        6) 提交任务

        7) 关闭线程池

        异步模式:Worker Thread 工作线程


ThreadPoolExecutor

1) 线程池状态

  • ThreadPoolExecutor 有五种状态,用一个 int 变量的高三位来保存线程池的状态,低 29 位来保存线程池中的线程数量

为什么用一个变量保存两个值??

将两个信息存储在一个原子变量 ctl 中,将线程池状态和线程数量合二为一,这样就可以用一次 CAS 操作同时对两个值进行赋值,保证了并发安全

  • 线程池状态大小比较(从数字上来看):TERMINATED > TIDYING > STOP > SHUTDOWN > RUNNING

2) 构造方法

3) 固定数量线程池 FixedThreadPool

  • 核心线程数 == 最大线程数
  • 没有超时时间:非核心线程不会被回收
  • 使用无界队列:不会触发非核心线程的创建、有可能发生 OOM
  • 适用场景:适用于任务量已知,相对耗时的任务

4) 带缓冲线程池 CacheThreadPool

  • 核心线程数为 0,最大线程数 Integer.MAX_VALUE,所有线程都是非核心线程(救急线程),可以在这个范围内不停创建新的线程
  • 超时时间是 60 秒,所有线程如果空闲了 60s 之后都会被回收
  • 阻塞队列使用的是同步队列 SynchronousQueue:没有容量,如果没有线程来取任务就放不进去,放任务的线程会阻塞知道有非核心线程来取任务
  • 非核心线程处理完任务之后,可以到同步队列中取任务
  • 线程池表现:随着任务数量增大,线程数量不断增大,没有上限,当线程执行完任务并空闲 1min 后,线程就会被销毁
  • 适用场景:任务密集且任务执行时间短

5) 单线程线程池 SingleThreadExecutor

  • 核心线程数 == 最大线程数 ==1,只有 1 个核心线程来执行任务,任务执行完毕也不会释放
  • 任务数量大于 1 时,会直接放入无界队列等待线程执行
  • 适用场景:希望任务按顺序执行,按照队列中的顺序排队执行
  • 和自己创建一个线程来执行任务的区别
    • 自己创建的线程如果因为执行任务失败而终止,没有补救措施,任务队列中的任务也没有别的线程来执行了
    • 单线程线程池中的线程如果因为执行任务失败而终止,线程池还会创建一个新的线程来执行任务,任务队列中的任务还是可以得到执行,线程池的正常工作可以得到保证
  • 和 new FixedThreadPool(1) 的区别:

6) 提交任务

  • void execute(Runnable r):执行任务,接收 Runnable,没有返回值
  • submit:提交任务到线程池中,接收 Callable(Callable 有返回值,Runnable 没有返回值),用 future 获取返回值

7) 关闭线程池

1. void shutdown()

  • 线程池状态变为 SHUTDOWN
  • 不会接收新任务
  • 不会中断正在执行的任务(已提交的任务会执行完=>正在执行的 + 已在队列中的)
  • 不会阻塞调用 shutdown() 的线程(主线程)的执行
  • 打断空闲线程

2. List<Runnable> shutdownNow()

  • 线程池状态变为 STOP
  • 不会接收新任务
  • 用 interrupt 中断所有线程,包括正在执行任务的线程和空闲的线程
  • 返回队列中尚未执行的任务 List<Runnable>

3. 其他方法

异步模式:Worker Thread 工作线程

  • 定义:让有限的资源(工作线程)轮流异步处理无限多的任务
  • 注意:不同类型的任务类型使用不同的线程池,可以 避免饥饿,提升效率

饥饿:不同于 第四章 共享模型——管程 (yuque.com)-线程活跃性中的饥饿,线程池中的饥饿是由于线程不足无法执行任务导致的

  • 固定大小 的线程池才会有饥饿现象,带缓冲线程池(corePoolSize = 0, maxPoolSize = Integer.MAX_VALUE)不会

两个线程都去点餐了,点完餐会等其他线程去做菜,做完菜后才可以上菜,但是线程池中已经 没有多余的线程 去做菜了,导致这两个点餐的线程都在这死等做菜,导致饥饿现象,注意这不是死锁,因为不是相互等待

  • 上面问题的原因:不同类型的任务都提交一个线程池当中,且任务之间有 依赖 关系
  • 解决方法:不同的任务类型使用不同的线程池,各司其职
  • 21
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值