27.线程池ThreadPoolExecutor实战及其原理分析

线程池的参数设置

  • corePoolSize:核心线程数,表示线程池中的常驻线程的个数
  • maximumPoolSize:最大线程数,表示线程池中能开辟的最大线程个数

线程池执行任务的类型

执行时间 = 任务总时间 + 上下文切换时间

  • CPU密集型任务,比如找出1-1000000中的素数
    • 设置线程数为:CPU核心数 + 1
  • IO密集型任务,比如文件IO、网络IO
    • 设置线程数为:2*CPU核心数
  • 混合型任务
    • 线程数 = CPU核心数 *( 1 + 线程等待时间 / 线程运行总时间 )

以上是理论,实际工作中如果要确定线程数,最好是压测。

总结

  1. CPU密集型任务:CPU核心数+1,这样既能充分利用CPU,也不至于有太多的上下文切换成本
  2. IO型任务:建议压测,或者先用公式计算出一个理论值(理论值通常都比较小)
  3. 对于核心业务(访问频率高),可以把核心线程数设置为我们压测出来的结果,最大线程数可以等于核心线程数,或者大一点点,比如我们压测时可能会发现500个线程最佳,但是600个线程时也还行,此时600就可以为最大线程数
  4. 对于非核心业务(访问频率不高),核心线程数可以比较小,避免操作系统去维护不必要的线程,最大线程数可以设置为我们计算或压测出来的结果。

为什么使用线程池

节省开启和销毁线程的消耗

线程池执行任务的具体流程

注意:提交一个Runnable时,不管当前线程池中的线程是否空闲,只要数量小于核心线程数就会创建新线程。

注意:ThreadPoolExecutor相当于是非公平的,比如队列满了之后提交的Runnable可能会比正在排队的Runnable先执行。

  • 当线程数 < corePoolSize,创建新线程,执行Runnable。
    • Runnable加入到workQueue
      • workQueue未满,入队,等待执行
      • 当线程数 < maximumPoolSize,创建新线程,执行Runnable。否则拒绝任务。

线程池中的线程是如何关闭

Thread类提供了一个stop(),但是标记了@Deprecated

建议通过自定义一个变量,或者通过中断 interrupt() 来停掉一个线程

线程池为什么一定得是阻塞队列

线程为了不自然消亡,就会阻塞在获取队列任务,通过这种方法能最终确保,线程池中能保留指定个数的核心线程数。

线程发生异常,会被移出线程池吗

在源码中,当执行任务时出现异常时,最终会执行processWorkerExit(),执行完这个方法后,当前线程也就自然消亡了,但会再新增一个线程,这样就能维持住固定的核心线程数。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值