线程池类型场景和问题

https://mp.weixin.qq.com/s/Cv5gTiz9RORnesoQmyROIw

 

Executors线程工厂类
1、Executors.newCachedThreadPool();
说明:

   创建的线程池核心线程0 , 最大线程是Integer.MaxValue。 线程空闲存活时间1分钟。 默认异常拒绝策略,使用SynchronousQueue队

特点:

  每次添加任务如果没有空闲线程就会新建一个线程去执行。
  SynchronousQueue是阻塞队列,加入任务的线程会阻塞住,直到其它线程从中取走任务才会结束阻塞
  线程创建上限近乎无限

队列:

  SynchronousQueue

适用场景:

  所以它适用于任务加入比较稳当且加入间隔短的场景

实现:

  new ThreadPoolExecutor(0,Integer.MAX_VALUE,60L,TimeUnit.SECONDS,new SynchronousQueue());

问题:

  可能在大量请求的时候,创建了过多的线程,导致的效率低下,甚至OOM。

 

2、Executors.newFixedThreadPool(int);
说明: 

  核心线程和最大线程数是你传入的参数。 其他参数和 Executors.newSingleThreadExecutor一样

实现:

  new ThreadPoolExecutor(nThreads, nThreads,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue());

阻塞队列

  无界的 LinkedBlockingQueue 阻塞队列

问题:

  也是有可能造成队列积压,以至于导致OOM的问题,所以,我们在使用时要合理的设置线程数。

  newFixedThreadPool线程池的核心线程数是固定的,它使用了近乎于无界的 LinkedBlockingQueue 阻塞队列。(平安问过

  当核心线程用完后,任务会入队到阻塞队列,如果任务执行的时间比较长,没有释放,会导致越来越多的任务堆积到阻塞队列,最后导致机器的内存使用不停的飙升,造成JVM OOM。

(参考: https://www.cnblogs.com/hulianwangjiagoushi/p/11498353.html)

 

3、Executors.newSingleThreadExecutor();
说明:

  创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照顺序执行。

特点:

  只有一个线程

  近乎可以接收无限任务的队列, 可以堆积大量任务

  适用于任务持续加入但是任务数并不多的场景

实现:

  new ThreadPoolExecutor(1,1,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue())

问题:

  如果有其他请求任务时,此时线程没有空闲,就会将此任务放到队列中等待执行。

  主要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至OOM。
 

4、Executors.newScheduledThreadPool(int);
说明:

  创建一个定长线程池,支持定时及周期性任务执行。

特点:

  核心线程是传入的参数,最大线程是int上线, 默认存活时间是10毫秒, 任务队列使用自己实现的DelayedWorkQueue, 拒绝策略异常策略

  加入任务的时候,会把任务和定时时间构建一个RunnableScheduledFuture对象,再把这个对象放入DelayedWorkQueue队列中,

  DelayedWorkQueue是一个有序队列, 他会根据内部的RunnableScheduledFuture的运行时间排序内部对象。

  任务加入后就会启动一个线程。 这个线程会从DelayedWorkQueue中获取一个任务。

阻塞队列:

  DelayedWorkQueue内部是按照时间从前完后获取任务的。如果任务的中的时间还没有到。 获取的就是null。

   获取任务结束,线程会休眠10毫秒。所以这个定时任务的执行最小间隔是10毫秒的。

内部实现

  new ScheduledThreadPoolExecutor(corePoolSize)

问题:

  主要问题是线程数最大数是Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至OOM。

posted @ 2021-10-08 16:47  李荣先辈Java  阅读(171)  评论(0编辑  收藏  举报