Java并发编程之阻塞队列与线程池

193 篇文章 9 订阅
107 篇文章 0 订阅

阻塞队列

Java中的阻塞队列:
ArrayBlockingQueue
LinkedBlockingQueue
SynchronousQueue
DelayQueue
DelayedWorkQueue
PriorityBlockingQueue
LinkedTransferQueue
LinkedBlockingDeque

1.SynchronousQueue

private static ExecutorService cachedThreadPool = new ThreadPoolExecutor(4, Runtime.getRuntime().availableProcessors() * 2, 0, TimeUnit.MILLISECONDS, new SynchronousQueue<>(), r -> new Thread(r, "ThreadTest"));

SynchronousQueue没有容量,是无缓冲等待队列,是一个不存储元素的阻塞队列,会直接将任务交给消费者,必须等队列中添加的元素被消费后才能继续添加新的元素。

2.LinkedBlockingQueue

private static ExecutorService cachedThreadPool = new ThreadPoolExecutor(4, Runtime.getRuntime().availableProcessors() * 2, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), r -> new Thread(r, "ThreadTest"));

3.ArrayBlockingQueue

 private static ExecutorService cachedThreadPool = new ThreadPoolExecutor(4, Runtime.getRuntime().availableProcessors() * 2, 0, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(32), r -> new Thread(r, "ThreadTest"));

ArrayBlockingQueue是一个有界缓存等待队列,可以指定缓存队列的大小,当正在执行的线程数等于corePoolSize时,多余的元素缓存在ArrayBlockingQueue队列中等待有空闲的线程时继续执行,当ArrayBlockingQueue已满时,加入ArrayBlockingQueue失败,会开启新的线程去执行,当线程数已经达到最大的maximumPoolSizes时,再有新的元素尝试加入ArrayBlockingQueue时会报错。

线程池

corePoolSize:

线程池中会维护一个最小的线程数量,即使这些线程处理空闲状态,他们也不会被销毁,除非设置了allowCoreThreadTimeOut。

线程池的基本大小,即在没有任务需要执行的时候线程池的大小,并且只有在工作队列满了的情况下才会创建超出这个数量的线程。这里需要注意的是:在刚刚创建ThreadPoolExecutor的时候,线程并不会立即启动,而是要等到有任务提交时才会启动,除非调用了prestartCoreThread/prestartAllCoreThreads事先启动核心线程。再考虑到keepAliveTime和allowCoreThreadTimeOut超时参数的影响,所以没有任务需要执行的时候,线程池的大小不一定是corePoolSize。

maximumPoolSize:

线程池中允许的最大线程数,线程池中的当前线程数目不会超过该值。如果队列中任务已满,并且当前线程个数小于maximumPoolSize,那么会创建新的线程来执行任务。这里值得一提的是largestPoolSize,该变量记录了线程池在整个生命周期中曾经出现的最大线程个数。为什么说是曾经呢?因为线程池创建之后,可以调用setMaximumPoolSize()改变运行的最大线程的数目。

poolSize:

线程池中当前线程的数量,当该值为0的时候,意味着没有任何线程,线程池会终止;同一时刻,poolSize不会超过maximumPoolSize。

keepAliveTime

keepAliveTime的jdk中的解释为:当线程数大于核心线程数时,多余的空闲线程终止前等待新任务的最长时间。

先引用一句我觉得相对说的比较明白的含义:当线程空闲时间达到keepAliveTime,该线程会退出,有两个疑问:1、线程为什么会空闲 2、线程为什么要退出
如果我们不能把线程池各个参数的来龙去脉都梳理清楚其实是很难明白keepAliveTime的含义的。
我们来举例说明:
核心线程数10,最大线程数30,keepAliveTime是3秒,随着任务数量不断上升,线程池会不断的创建线程,直到到达核心线程数10,就不创建线程了,这时多余的任务通过加入阻塞队列来运行,当超出阻塞队列长度+核心线程数时,这时不得不扩大线程个数来满足当前任务的运行,这时就需要创建新的线程了(最大线程数起作用),上限是最大线程数30,那么超出核心线程数10并小于最大线程数30的可能新创建的这20个线程相当于是“借”的,如果这20个线程空闲时间超过keepAliveTime,就会被退出。

我们来看开头提到的两个问题:
1、线程为什么会空闲
2、线程为什么要退出

答:
1、没有任务时线程就会空闲下来,在线程池中任务是任务(Runnale),线程是线程(Worker)。
2、通常超出核心线程的线程是“借”的,也就是说超出核心线程的情况算是一种能够预见的异常情况,并且这种情况并不常常发生(如果常常发生,那我想你应该调整你的核心线程数了),所以这种不经常发生而创建的线程为了避免资源浪费就应该要退出。

我们需要看一下java.util.concurrent.ThreadPoolExecutor#getTask源码来验证上面一段话的含义:

int wc = workerCountOf(c);

// Are workers subject to culling? 是否屠宰workers
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize; //当allowCoreThreadTimeOut为true或者当前任务数超过核心线程数时,timed为true

......

try {
	Runnable r = timed ?
		workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :	//如果timed为true说明worker有可能要被关闭,这里调用的代码含义:如果超过keepAliveTime纳秒还没取到任务,就返回null,后面会调用processWorkerExit把worker关闭
		workQueue.take();//否则任务队列为空就阻塞在这里,直到任务队列再有任务
	if (r != null)
		return r;
	timedOut = true;

......

10个核心线程会不会退出,由下面的参数决定:allowCoreThreadTimeout:是否允许核心线程空闲退出,默认值为false。

当keepAliveTime设置为0时到底是空闲线程直接退出还是不退出

上文代码workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS)证明,是直接退出,而不是永远不退出。

这样我们就需要注意了,这个值设置为0 并不是个很好的做法(除非场景中任务数量极少能超出核心线程数),如果任务数频繁超出核心线程数,这个值需要评估设定为合理值尽量避免线程开启关闭的动作。

allowCoreThreadTimeOut

当设置allowCoreThreadTimeOut(true)时,线程池中的corePoolSize线程如果空闲时间达到keepAliveTime也将关闭

参考:
JAVA并发编程下的阻塞队列与线程池
线程池的三种队列区别:SynchronousQueue、LinkedBlockingQueue 和ArrayBlockingQueue
Android 多线程之阻塞队列

理解ThreadPoolExecutor源码(一)线程池的corePoolSize、maximumPoolSize和poolSize
Java线程池七个参数详解
合理配置线程池,corePoolSize的合理设置
java中四种线程池及poolSize、corePoolSize、maximumPoolSize

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值