打赏

如何使用好线程池?

如何使用好线程池?

  • 线程个数大小的设置
  • 线程池相关参数的配置
  • 利用Hook嵌入你的行为
  • 线程池的关闭

线程池数量的设置,你的依据是什么?

计算机密集型

应用需要非常多的CPU计算资源,避免过多的线程上下文切换

线程数 = CPU核数+1,已可以设置为CPU核数*2,还要看JDK的版本以及CPU配置(服务器的CPU有超线程)

IO密集型

Web应用,涉及到大量的网络传输,不仅如此,与数据库,与缓存间的交互也涉及到IO,一旦发生IO,线程就会处于等待状态,当IO结束后,数据准备好后,线程才会继续执行。对于IO密集型的应用,我们可以多设置线程池中线程的数量,这样就能让等待IO的这段时间内,线程可以去做其它事,提高并发处理效率。线程上下文切换数有代价的

线程数 = CPU核数/(1-阻塞系数) 这个阻塞系数一般为0.8~0.9之间。

套用公司:对于双核CPU来说,比较理想的线程数就是20,当然这不是绝对的,需要根据实际情况以及实际业务来调整:final int poolSIze = (int)(copCore/(1-0.9))

线程池相关参数如何配置?

  • 高压线:
    • 我们使用线程池的时候都不要选择没有上限限制的配置项
  • 第一 我们不要去使用没有上限的线程池和设置无界队列!
  • 比如,newCachedThreadPool的设置与无界队列因为某些不可预期的情况,线程池会出现系统异常,导致线程暴增的情况或者任务队列或者任务队列不断膨胀,内存耗尽导致系统崩溃。我们建议自定义线程池来避免改问题,这是在使用线程池的首要选择。小心无大错,千万别过度自信。
  • 第二 合理设置线程数量、和线程空闲回收时间,根据具体的任务执行周期和时间去设定,避免频繁的回收和创建,虽然我们使用线程池的目的是为了提升系统性能和吞吐量,但是也要考虑下系统的稳定性,不然出现不可预期问题会很麻!
  • 第三,根据实际场景,选择适用于自己的拒绝策略。进行补偿,不要乱用JDK支持的自动补偿机制~尽量采用自定义的拒绝策略去进行兜底!

利用Hook去嵌入你的行为

  • 利用Hook,留下线程池执行的执行轨迹
  • ThreadPoolExcutor提供了protected类型可以被覆盖的钩子方法,运行用户在执行任务之前或执行之后做一些事情。我们可以通过它来实现比如初始化ThreadLocal、收集统计信息、如记录日志等操作,这类Hook如BeforeExcute和afterExecute。另外还有一个Hook可以用来在任务呗执行完的时候让用户插入逻辑,如reminated。
  • Hook方法执行失败,则内部的工作线程的执行将会失败或者中断。

关闭线程池

  • 内容当线程池不在被引用并且工作线程数为0的时候,线程池将被终止。我们也可以调用shutdown来手动终止线程池。如果我们忘记调用shutdown,为了让线程资源被释放,我们还可以使用keepAliveTime和allowShutdownHook方法,手工去调用线程池的关闭方法!
  • 当然,最稳妥的方式是使用虚拟机Runtime.getRuntime().addShutdownHook方法,手动去调用线程池关闭方法。
posted @ 2018-12-17 04:34  JupiterMouse  阅读(234)  评论(0编辑  收藏  举报