动态设置的注意点有哪些?
调整的时候可能会出现核心线程数调整之后无效的情况,比如下面这种:
改变之前的核心线程数是 2,最大线程数为 5,我们动态修改核心线程数为 10。
但是从日志还是可以看出,修改之后核心线程数确实变成了 10,但活跃线程数还是为 5。
而且我调用了 prestartCoreThread 方法,该方法见名知意,你也知道是启动所有的核心线程数,所有不存在线程没有创建的问题。
这是为什么呢?
源码之下无秘密,我带你去看一眼:
java.util.concurrent.ThreadPoolExecutor#getTask
在这个方法中我们可以看到,如果工作线程数大于最大线程数,则对工作线程数量进行减一操作,然后返回 null。
所以,这个地方的实际流程应该是: 创建新的工作线程 worker,然后工作线程数进行加一操作。 运行创建的工作线程 worker,开始获取任务 task。 工作线程数量大于最大线程数,对工作线程数进行减一操作。 返回 null,即没有获取到 task。 清理该任务,流程结束。
这样一加一减,所以真正在执行任务的工作线程数的数量一直没有发生变化,也就是最大线程数。
怎么解决这个问题呢?
答案已经呼之欲出啦。
设置核心线程数的时候,同时设置最大线程数即可。其实可以把二者设置为相同的值:
这样,活动线程数就能正常提高了。
有的小伙伴就会问了:如果调整之后把活动线程数设置的值太大了,岂不是业务低峰期我们还需要人工把值调的小一点?
不存在的,还记得前面介绍 corePoolSize 参数的含义时的注解吗:
当 allowCoreThreadTimeOut 参数设置为 true 的时候,核心线程在空闲了
keepAliveTime 的时间后也会被回收的,相当于线程池自动给你动态修改了。
如何动态指定队列长度?
前面介绍了最大线程数和核心线程数的动态设置,但是你发现了吗,并没有设置队列长度的 set 方法啊?
有的小机灵鬼说先获取 Queue 对象出来再看一下呢?
还是没有,这可咋整呢?
首先我们看一下为什么没有提供队列长度的 set 方法呢:
因为队列的 capacity 是被 final 修饰了呀。
但是美团的那篇文章明明说了,他们也支持队列的动态调整呀:
可是没有详细说明,但是别着急,接着看后面的内容可以发现他们有一个名字为 ResizableCapacityLinkedBlockIngQueue 的队列:
很明显,这是一个自定义队列了。
我们也可以按照这个思路自定义一个队列,让其可以对 Capacity 参数进行修改即可。
操作起来也非常方便,把 LinkedBlockingQueue 粘贴一份出来,修改个名字,然后把 Capacity 参数的 final 修饰符去掉,并提供其对应的 get/set 方法。
然后在程序里面把原来的队列换掉:
运行起来看看效果:
可以看到,队列大小确实从 10 变成了 100,队列使用度从 100% 降到了 9%。
我后来去看了美团的那篇文章下面的评论,有个评论是这样的:
果然不出我所料。
这个过程中涉及到的面试题有哪些?
问题一:线程池被创建后里面有线程吗?如果没有的话,你知道有什么方法对线程池进行预热吗?
线程池被创建后如果没有任务过来,里面是不会有线程的。如果需要预热的话可以调用下面的两个方法:
全部启动:
仅启动一个:
问题二:核心线程数会被回收吗?需要什么设置?
核心线程数默认是不会被回收的,如果需要回收核心线程数,需要调用下面的方法:
allowCoreThreadTimeOut 该值默认为 false。
最后说一句(求关注)
点个赞吧,周更很累的,不要白嫖我,需要一点正反馈。
才疏学浅,难免会有纰漏,如果你发现了错误的地方,由于本号没有留言功能,还请你加我微信给我指出来,我对其加以修改。(我每篇技术文章都有这句话,我是认真的说的。)
感谢您的阅读,我坚持原创,十分欢迎并感谢您的关注。
我是why技术,一个不是大佬,但是喜欢分享,又暖又有料的四川好男人。
欢迎关注公众号【why技术】,坚持输出原创。分享技术、品味生活,愿你我共同进步。