7000字+24张图带你彻底弄懂线程池(五)

pivoteic
发布于 2022-6-17 16:50
浏览
0收藏

 

七、线程池的关闭

 

线程池提供了shutdown和shutdownNow两个方法来关闭线程池。

 

shutdown方法

7000字+24张图带你彻底弄懂线程池(五)-鸿蒙开发者社区

就是将线程池的状态修改为SHUTDOWN,然后尝试打断空闲的线程(如何判断空闲,上面在说Worker继承AQS的时候说过),也就是在阻塞等待任务的线程。

 

shutdownNow方法

7000字+24张图带你彻底弄懂线程池(五)-鸿蒙开发者社区

就是将线程池的状态修改为STOP,然后尝试打断所有的线程,从阻塞队列中移除剩余的任务,这也是为什么shutdownNow不能执行剩余任务的原因。

 

所以也可以看出shutdown方法和shutdownNow方法的主要区别就是,shutdown之后还能处理在队列中的任务,shutdownNow直接就将任务从队列中移除,线程池里的线程就不再处理了。

 

八、线程池的监控

 

在项目中使用线程池的时候,一般需要对线程池进行监控,方便出问题的时候进行查看。线程池本身提供了一些方法来获取线程池的运行状态。

  • getCompletedTaskCount:已经执行完成的任务数量
  • getLargestPoolSize:线程池里曾经创建过的最大的线程数量。这个主要是用来判断线程是否满过。
  • getActiveCount:获取正在执行任务的线程数据
  • getPoolSize:获取当前线程池中线程数量的大小

 
除了线程池提供的上述已经实现的方法,同时线程池也预留了很对扩展方法。比如在runWorker方法里面,在执行任务之前会回调beforeExecute方法,执行任务之后会回调afterExecute方法,而这些方法默认都是空实现,你可以自己继承ThreadPoolExecutor来扩展重写这些方法,来实现自己想要的功能。

 

九、Executors构建线程池以及问题分析

 

JDK内部提供了Executors这个工具类,来快速的创建线程池。

 

1)固定线程数量的线程池:核心线程数与最大线程数相等

7000字+24张图带你彻底弄懂线程池(五)-鸿蒙开发者社区

2)单个线程数量的线程池

7000字+24张图带你彻底弄懂线程池(五)-鸿蒙开发者社区

3)接近无限大线程数量的线程池

7000字+24张图带你彻底弄懂线程池(五)-鸿蒙开发者社区

4)带定时调度功能的线程池

7000字+24张图带你彻底弄懂线程池(五)-鸿蒙开发者社区

虽然JDK提供了快速创建线程池的方法,但是其实不推荐使用Executors来创建线程池,因为从上面构造线程池可以看出,newFixedThreadPool线程池,由于使用了LinkedBlockingQueue,队列的容量默认是无限大,实际使用中出现任务过多时会导致内存溢出;newCachedThreadPool线程池由于核心线程数无限大,当任务过多的时候,会导致创建大量的线程,可能机器负载过高,可能会导致服务宕机。

 

十、线程池的使用场景

 

在java程序中,其实经常需要用到多线程来处理一些业务,但是不建议单纯使用继承Thread或者实现Runnable接口的方式来创建线程,那样就会导致频繁创建及销毁线程,同时创建过多的线程也可能引发资源耗尽的风险。所以在这种情况下,使用线程池是一种更合理的选择,方便管理任务,实现了线程的重复利用。所以线程池一般适合那种需要异步或者多线程处理任务的场景。

 

十一、实际项目中如何合理的自定义线程池

 

通过上面分析提到,通过Executors这个工具类来创建的线程池其实都无法满足实际的使用场景,那么在实际的项目中,到底该如何构造线程池呢,该如何合理的设置参数?

 

1)线程数


线程数的设置主要取决于业务是IO密集型还是CPU密集型。

 

CPU密集型指的是任务主要使用来进行大量的计算,没有什么导致线程阻塞。一般这种场景的线程数设置为CPU核心数+1。

 

IO密集型:当执行任务需要大量的io,比如磁盘io,网络io,可能会存在大量的阻塞,所以在IO密集型任务中使用多线程可以大大地加速任务的处理。一般线程数设置为 2*CPU核心数

 

java中用来获取CPU核心数的方法是:Runtime.getRuntime().availableProcessors();


2)线程工厂


一般建议自定义线程工厂,构建线程的时候设置线程的名称,这样就在查日志的时候就方便知道是哪个线程执行的代码。

 

3)有界队列

一般需要设置有界队列的大小,比如LinkedBlockingQueue在构造的时候就可以传入参数,来限制队列中任务数据的大小,这样就不会因为无限往队列中扔任务导致系统的oom。

 

文章转自公众号:三友的java日记

标签
已于2022-6-17 16:50:38修改
收藏
回复
举报
回复
    相关推荐