《12个真实项目实战带你玩转Java并发编程》 笔记三 ThreadPoolExecutor与生产者消费者模式

一、生产者-消费者模式

 模型如下图,生产者创建任务并提交到任务队列中,消费者从任务队列中获取任务并消费,类似MQ,但这里提交到队列中的任务可以封装成FutureTask对象,这样消费者可以获取到执行结果

下面贴出一段示例代码,put和take时都会阻塞,这样就不会发生溢出的问题

二、ThreadPoolExecutor

 ThreadPoolExecutor的构造参数中有这么几个核心参数,具体作用就不再解释,线程池本身的设计,也是用到了生产者-消费者模式,execute方法就是生产任务,blockingQueue就是阻塞队列,线程数就是消费者

线程池的大小可以按下图规则设置,通过Runtime.getRuntime().availableProcessors()就可以很方便的获取到JVM所在机器的CPU个数,从而方便我们指定具体的线程个数

工作队列通常有无界队列、有界队列、同步队列三种类型,每个队列都有它自己的特点和用途,如下图所示

当所有线程都在工作,等待队列占满了后,如果还有任务进来,就会执行拒绝策略。ThreadPoolExecutor自带了4种拒绝策略

默认是使用的AbortPolicy策略,运行效果如下,会直接报异常

 当使用CallerRunsPolicy拒绝策略后,效果如下。发生阻塞后(即阻塞队列也满了),调用submit这个方法的线程也会参与执行任务(在下图中就是主线程),所以一开始是有6个线程在执行,main线程也无法结束。当第一批6个执行完,第二批5个被线程池执行,此时阻塞队列里还有9个任务,没有发生阻塞,所以主线程没有执行。所以使用CallerRunsPolicy一定要特别注意调用线程阻塞这个问题!

三、ThreadPoolExecutor的shutdown和shutdownNow

两者都会尝试中止线程,但都只能中止阻塞状态的线程,正在运行的线程无法中止。区别在于,shutdown是将线程运行状态设置为shutdown,不再接收新的任务,但还会把阻塞队列中的任务执行完。shutdownNow是将线程运行状态设置为stop,不会再执行阻塞队列中的任务,而是把这些任务返回成List,并且如果任务是阻塞状态的,会立即结束

四、如何优雅的结束线程

先调用shutdown方法,不再接收新任务。然后awaitTermination等待10秒,如果线程池还没有关闭,调用shutdownNow,移除阻塞队列中的任务

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值