干货--并发编程提高-线程池痛点(三十二)

线程池被创建后里面有线程吗?如果没有的话,你知道有什么方法对线程池进行预热吗?

线程池被创建后如果没有任务过来,里面是不会有线程的。如果需要预热的话可以调用下面的两个方法:

全部启动:

仅启动一个:

核心线程数会被回收吗?需要什么设置?

核心线程数默认是不会被回收的,如果需要回收核心线程数,需要调用下面的方法:

allowCoreThreadTimeOut 该值默认为 false。

线程池拒绝策略如何选择的?

注意:线程池使用FutureTask的时候如果拒绝策略设置为了DiscardPolicy和DiscardOldestPolicy并且在被拒绝的任务的Future对象上调用无参get方法那么调用线程会一直被阻塞。

问题复现 工作中遇到的坑

AbortPolicy:丢弃任务并抛出RejectedExecutionException异常 (默认)

DiscardPolicy:也是丢弃任务,但是不抛出异常

DiscardOldestPolicy:丢弃队列最前面的任务,执行后面的任务

CallerRunsPolicy:由调用线程处理该任务 

及自定义,但是丢弃任务有个问题如下:

运行结果:

start runable one

task one finish null

start runable two

task two finish null

创建了一个单线程并且队列元素个数为1的线程池,并且拒绝策略设置为了DiscardPolicy;先提交任务one,这个任务会使用唯一的一个线程进行执行,任务在打印 start runable one后会阻塞该线程5s;再向线程池提交了一个任务two,这时候会把任务two放入到阻塞队列;提交任务three时,由于队列已经满了则会触发拒绝策略丢弃任务three。

  从运行结果看在任务one阻塞的5s内,主线程执行到了代码(5)等待任务one执行完毕,当任务one执行完毕后代码(5)返回,主线程打印出task one finish null。之后线程池的唯一线程会去队列里面取出任务two并执行所以输出start runable two然后代码(6)会返回,这时候主线程输出task two finish null,然后执行代码(7)等待任务three执行完毕,从执行结果看代码(7)会一直阻塞不会返回。

  至此问题产生,如果把拒绝策略修改为DiscardOldestPolicy也会存在有一个任务的get方法一直阻塞只是现在是任务two被阻塞:

start runable one

task one finish null

start runable three

但是如果拒绝策略设置为默认的AbortPolicy则会抛出RejectedExecutionException并正常返回。

问题分析

要分析这个问题需要看下线程池的submit方法里面做了什么,submit方法代码如下:

newTaskFor()把Runnable转为FutureTask对象,FutureTask实现RunnableFuture接口,继续跟execute:

也就是说当future的状态>COMPLETING时候调用get方法才会返回,而明显DiscardPolicy策略在拒绝元素的时候并没有设置该future的状态,后面也没有其他机会可以设置该future的状态,所以future的状态一直是NEW,所以一直不会返回,同理DiscardOldestPolicy策略也是这样的问题,最老的任务被淘汰时候没有设置被淘汰任务对于future的状态,也会导致一直不会返回。

那么默认的AbortPolicy策略为啥没问题那?来看AbortPolicy策略代码:

所以当使用Future的时候,尽量使用带超时时间的get方法,这样即使使用了DiscardPolicy拒绝策略也不至于一直等待,等待超时时间到了会自动返回的,如果非要使用不带参数的get方法则可以重写DiscardPolicy的拒绝策略在执行策略时候设置该Future的状态大于COMPLETING即可,但是查看FutureTask提供的方法发现只有cancel方法是public的并且可以设置FutureTask的状态大于COMPLETING,重写拒绝策略具体代码可以如下:

使用这个策略时候,由于report方法中对cancel的任务上会抛出CancellationException异常,所以在get()时使用try-catch捕获异常。运行后发现程序能正常退出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值