java 线程池场景

Posted FireCool

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java 线程池场景相关的知识,希望对你有一定的参考价值。

java 一共含有四种线程池: newCachedThreadPool, newFixedThreadPool, newSingleThreadExecutor, newScheduledThreadPool。

newCachedThreadPool:顾名思义是一种可缓存的线程池, 线程池除了维护初始大小的线程外,当任务数量超出线程池大小时,便会新建线程, 而且当线程完成任务之后不会马上销毁,而是会保留一段时间(默认60s),这种极大的减少了线程创建和销毁的资源消耗, 当这种线程池的弊端是 线程最大值过大, 如果用于高并发且任务较长场景,很容易将内存全部吃光。 所以使用于执行短期异步小任务,或者并发量不高的场景。

newFixedThreadPool :是基于无界队列的线程池, 维护的线程数量是固定的,如果线程均在繁忙状态,则新任务会放入无界队列里。 适用于长期任务。 如果用于短期任务,任务数量 < 线程池数量时,性能不会跟newCachedThreadPool太大的区别,但是超出时, 因为是短期的, 所以任务会不断的被放入队列,又被取出, 时间间隔很短,并且过多的短期任务放入队列中,回使得内存吃紧,当任务数量过多时会造成很大的资源浪费。

newSingleThreadExecutor:顾名思义是只有一个单线程的线程池,具体场景不太清晰, 按照线程含义来看,适用于需要按顺序(FIFO, LIFO, 优先级)的执行任务的场景,以及thread confinement(变量只能由特定线程访问)的要求。

newScheduleThreadPool :如果所有线程均处于繁忙状态,对于新任务会进入DelayedWorkQueue队列中,这是一种按照超时时间排序的队列结构。这个线程的应用场景就很容易知道了, 需要周期性执行的任务使用该线程池。

 

线程池任务执行流程:

  当线程池小于corePoolSize时,新提交任务将创建一个新线程执行任务,即使此时线程池中存在空闲线程。
  当线程池达到corePoolSize时,新提交任务将被放入workQueue中,等待线程池中任务调度执行
  当workQueue已满,且maximumPoolSize>corePoolSize时,新提交任务会创建新线程执行任务
  当提交任务数超过maximumPoolSize时,新提交任务由RejectedExecutionHandler处理
  当线程池中超过corePoolSize线程,空闲时间达到keepAliveTime时,关闭空闲线程
  当设置allowCoreThreadTimeOut(true)时,线程池中corePoolSize线程空闲时间达到keepAliveTime也将关闭
备注:

一般如果线程池任务队列采用LinkedBlockingQueue队列的话,那么不会拒绝任何任务(因为队列大小没有限制),这种情况下,ThreadPoolExecutor最多仅会按照最小线程数来创建线程,也就是说线程池大小被忽略了。

如果线程池任务队列采用ArrayBlockingQueue队列的话,那么ThreadPoolExecutor将会采取一个非常负责的算法,比如假定线程池的最小线程数为4,最大为8所用的ArrayBlockingQueue最大为10。随着任务到达并被放到队列中,线程池中最多运行4个线程(即最小线程数)。即使队列完全填满,也就是说有10个处于等待状态的任务,ThreadPoolExecutor也只会利用4个线程。如果队列已满,而又有新任务进来,此时才会启动一个新线程,这里不会因为队列已满而拒接该任务,相反会启动一个新线程。新线程会运行队列中的第一个任务,为新来的任务腾出空间。

这个算法背后的理念是:该池大部分时间仅使用核心线程(4个),即使有适量的任务在队列中等待运行。这时线程池就可以用作节流阀。如果挤压的请求变得非常多,这时该池就会尝试运行更多的线程来清理;这时第二个节流阀—最大线程数就起作用了。

 

ThreadPoolExecutor:

  private static int runStateOf(int c) { return c & ~CAPACITY; }    
  private static int workerCountOf(int c) { return c & CAPACITY; }   //因为ctl以(1<<29)开始递增,转化为以0开始递增的数字  例如 workerCOuntOf( (1<<29) +9 ) = 9;
  private static int ctlOf(int rs, int wc) { return rs | wc; }

 

参考文章:https://www.cnblogs.com/sachen/p/7401959.html

以上是关于java 线程池场景的主要内容,如果未能解决你的问题,请参考以下文章

java高并发之线程池

Java高并发之线程池详解

Java高并发之线程池详解

啥时候会使用线程池

Java并发-线程池篇-附场景分析

Java并发-线程池篇-附场景分析