看到一个魔改线程池,面试素材加一! (2)

我需要这样的一个线程池,它可以确保投递进来的任务按某个维度划分出任务,然后按照任务提交的顺序依次执行。这个线程池可以通过并行处理(多个线程)来提高吞吐量、又要保证一定范围内的任务按照严格的先后顺序来运行。

用我前面的例子,“按某个维度”就是人名,就是富贵和旺财这个维度。

请问你怎么做?

看到一个魔改线程池,面试素材加一!

一顿分析

我会怎么做?

首先,我可以肯定的是 JDK 的线程池是干不成这个事儿的。

因为从线程池原理的角度来说,并行和先后顺序它是不能同时满足的。

你明白我意思吧?

比如我要用线程池来保证先后顺序,那么它是这样的:

看到一个魔改线程池,面试素材加一!

只有一个线程的线程池,它可以保证先后顺序。

但是这玩意有意义吗?

有点意义,因为它并不占用主线程,但是意义不大,毕竟阉割了重要的“多线程”能力。

所以我们怎么在这个场景下把并行能力给提上去呢?

等等,我们好像已经有一个可以保证先后顺序的线程池了。

那么我们把它横向扩容,多搞几个,不就具备了并行的能力了吗?

看到一个魔改线程池,面试素材加一!

然后前面提到的“按某个维度”,如果有多个只有一个线程的线程池了,那我也可以按照这个维度去映射“维度”和“每个线程池”呀。

用程序来说就是这样的:

看到一个魔改线程池,面试素材加一!

标号为 ① 的地方就是搞了多个只有一个线程的线程池,目的是为了保证消费的顺序性。

标号为 ② 的地方就是通过一个 map 映射人名和线程池之间的关系。这里只是一个示意,比如我们还可以用用户号取模的方式去定位对应的线程池,比如用户号为奇数的用一个线程池,为偶数的用另外一个线程。

所以并不是“某个维度”里面有多少个数据就要定义多少个只有一个线程的线程池,它们也是可以复用的,这个地方有个小弯要转过来。

标号为 ③ 的地方就是根据名称去 map 里面去对应的线程池。

从输出结果来看,也是没有毛病的:

看到一个魔改线程池,面试素材加一!

看到这里有的朋友就要说:你这不是作弊吗?

不是说好一个线程池吗,你这都弄了多个了。

你要这个角度看问题的话,那就把路走窄了。

你要想着有一个大的线程池,里面又放了很多个只有一个线程的线程池。

这样格局就打开了。

看到一个魔改线程池,面试素材加一!

我上面的写法是一个非常简陋的 Demo,主要是引出这个方案的思路。

我要介绍的,就是基于这个思路搞出的一个开源项目。

是一位大公司的大佬写的,我看了一下源码,拍案叫绝:写的真他娘的好。

我先给你上一个使用案例和输出结果:

看到一个魔改线程池,面试素材加一!

从案例看起来,使用方式也是非常的简单。

和 JDK 原生的用法的差异点就是我框起来的部分。

首先搞一个 KeyAffinityExecutor 的对象,来代替原生的线程池。

KeyAffinityExecutor 其中涉及到一个单词,Affinity。

翻译过来有类同的含义:

看到一个魔改线程池,面试素材加一!

所以 KeyAffinityExecutor 翻译过来就是 key 类同的线程池,当你明白它的功能和作用范围后会觉得这个名字取的是针不戳。

接着是调用了 KeyAffinityExecutor 对象的 executeEx 方法,可以多传入一个参数,这个参数就是区分某一类相同任务的维度,比如我这里就给的是 name 字段。

从使用案例上看来,可以说封装的非常好,开箱即用。

看到一个魔改线程池,面试素材加一!

KeyAffinityExecutor用法

先说说这个类的用法吧。

其对应的开源项目地址是这个:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwfzjd.html