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

简介: 看到一个魔改线程池,面试素材加一!(下)

你到时候在这个地方打个断点,然后 Debug 看一眼,就非常明确了:


image.png

关于框起来的这部分的几个关键参数,我解释一下:

image.png

首先是 count 参数,就是我们定义的 3。那么 range(0,3),就是 0,1,2。

然后是 supplier,这玩意就是前面我们说的 executor 方法返回的 supplier 接口,可以看到里面封装的就是个线程池。

接着是里面有一个非常关键的操作 :map(ValueRef::new)。

这个操作里面的 ValueRef 对象,很关键:

com.github.phantomthief.pool.impl.KeyAffinityImpl.ValueRef


image.png

关键的地方就是这个对象里面的 concurrency 变量。

还记得最前面说的“挑选最闲置的执行器(线程池)”这句话吗?

怎么判断是否闲置?

靠的就是 concurrency 变量。

其对应的代码在这:

com.github.phantomthief.pool.impl.KeyAffinityImpl#select


image.png

能走到断点的地方,说明当前这个 key 是之前没有被映射过的,所以需要为其指定一个线程池。

而指定这个线程池的操作,就是循环这个 all 集合,集合里面装的就是 ValueRef 对象:


image.png

所以,comparingInt(ValueRef::concurrency) 方法就是在选当前所有的线程池,并发度最小的一个。

如果这个线程池从来没有用过或者目前没有任务在使用,那么并发度必然是 0 ,所有会被选出来。

如果所有线程池正在被使用,就会选 concurrency 这个值最低的线程池。

我这里只是给大家说一个大概的思路,如果要深入了解的话,自己去翻源码去。

如果你非常了解 lambdas 的用法的话,你会觉得写的真的很优雅,看起来很舒服。

如果你不了解 lambdas 的话...

那你还不赶紧去学?

另外我还发现了两个熟悉的东西。

朋友们,请看这是什么:

image.png

这难道不就是线程池参数的动态调整吗?

第二个是这样的:

image.png

RabbitMQ 里面的动态调整我也写过啊,也是强调过这三处地方:

  • 增加 {@link #setCapacity(int)} 和 {@link #getCapacity()}
  • {@link #capacity} 判断边界从 == 改为 >=
  • 部分 signal() 信号触发改为 signalAll()

另外作者还提到了 RabbitMQ 的版本里面会有导致 NPE 的 BUG 的问题。

这个就没细研究了,有兴趣的可以去对比一下代码,就应该能知道问题出在哪里。


说说 Dubbo


为什么要说一下 Dubbo 呢?

因为我似乎在 Dubbo 里面也发现了 KeyAffinityExecutor 的踪迹。

为什么说是似乎呢?

因为最终没有被合并到代码库里面去。

image.png

其对应的链接是这里:

https://github.com/apache/dubbo/pull/8975

这一次提交一共提交了这么多文件:

image.png


里面是可以找到我们熟悉的东西:


image.png

其实思路都是一样的,但是你会发现即使是思路一样,但是两个不同的人写出来的代码结构还是很不一样的。

Dubbo 这里把代码的层次分的更加明显一点,比如定义了一个抽象的 AbstractKeyAffinity 对象,然后在去实现了随机和最小并发两种方案。

在这些细节处上是有不同的。

但是这个代码的提供者最终没有用这些代码,而是拿出了一个替代方案:

image.png

https://github.com/apache/dubbo/pull/8999

在这一次提交里面,他主要提交了这个类:

org.apache.dubbo.common.threadpool.serial.SerializingExecutor

这个类从名字上你就知道了,它强调的是串行化。

带大家看看它的测试用例,你就知道它是怎么用的了:


image.png

首先是它的构造方法入参是另外一个线程池。

然后提交任务的时候用 SerializingExecutor 的 execute 方法进行提交。

在任务内部,干的事就是从 map 里面取出 val 对应的 key ,然后进行加 1 操作再放回去。

大家都知道上面的这个操作在多线程的情况是线程不安全的,最终加出来的结果一定是小于循环次数的。

但是,如果是单线程的情况下,那肯定是没问题的。

那么怎么把线程池映射为单线程呢?

SerializingExecutor 干得就是这事。

而且它的原理特别简单,核心代码就几行。

首先它自己搞了个队列:

image.png

提交进来的任务都扔到队列里面去。

接下来再一个个的执行。

怎么保证一个个的执行呢?

方法有很多,它这里是搞了个 AtomicBoolean 对象来控制:

image.png

这样就实现了把多线程任务搞成串行化的场景。

只是让我奇怪的是 SerializingExecutor 这个类目前在 Dubbo 里面并没有使用场景。

但是,如果你时候你就要实现这样奇怪的功能,比如别人给你一个线程池,但是到你的流程里面出入某种考虑,需要把任务串行化,这个时候肯定是不能动别人的线程池的,那么你可以想起 Dubbo 这里有一个现成的,比较优雅的、逼格较高的解决方案。


最后说一句


好了,看到了这里了, 转发、在看、点赞随便安排一个吧,要是你都安排上我也不介意。写文章很累的,需要一点正反馈。

给各位读者朋友们磕一个了:

微信图片_20220428223922.png

目录
打赏
0
0
0
0
6
分享
相关文章
阿里面试:5000qps访问一个500ms的接口,如何设计线程池的核心线程数、最大线程数? 需要多少台机器?
本文由40岁老架构师尼恩撰写,针对一线互联网企业的高频面试题“如何确定系统的最佳线程数”进行系统化梳理。文章详细介绍了线程池设计的三个核心步骤:理论预估、压测验证和监控调整,并结合实际案例(5000qps、500ms响应时间、4核8G机器)给出具体参数设置建议。此外,还提供了《尼恩Java面试宝典PDF》等资源,帮助读者提升技术能力,顺利通过大厂面试。关注【技术自由圈】公众号,回复“领电子书”获取更多学习资料。
面试大神教你:如何巧妙回答线程优先级这个经典考题?
大家好,我是小米。本文通过故事讲解Java面试中常见的线程优先级问题。小明和小华的故事帮助理解线程优先级:高优先级线程更可能被调度执行,但并非越高越好。实际开发需权衡业务需求,合理设置优先级。掌握线程优先级不仅能写出高效代码,还能在面试中脱颖而出。最后,小张因深入分析成功拿下Offer。希望这篇文章能助你在面试中游刃有余!
86 4
面试大神教你:如何巧妙回答线程优先级这个经典考题?
Java社招面试题:一个线程运行时发生异常会怎样?
大家好,我是小米。今天分享一个经典的 Java 面试题:线程运行时发生异常,程序会怎样处理?此问题考察 Java 线程和异常处理机制的理解。线程发生异常,默认会导致线程终止,但可以通过 try-catch 捕获并处理,避免影响其他线程。未捕获的异常可通过 Thread.UncaughtExceptionHandler 处理。线程池中的异常会被自动处理,不影响任务执行。希望这篇文章能帮助你深入理解 Java 线程异常处理机制,为面试做好准备。如果你觉得有帮助,欢迎收藏、转发!
288 14
面试中的难题:线程异步执行后如何共享数据?
本文通过一个面试故事,详细讲解了Java中线程内部开启异步操作后如何安全地共享数据。介绍了异步操作的基本概念及常见实现方式(如CompletableFuture、ExecutorService),并重点探讨了volatile关键字、CountDownLatch和CompletableFuture等工具在线程间数据共享中的应用,帮助读者理解线程安全和内存可见性问题。通过这些方法,可以有效解决多线程环境下的数据共享挑战,提升编程效率和代码健壮性。
185 6
Java线程调度揭秘:从算法到策略,让你面试稳赢!
在社招面试中,关于线程调度和同步的相关问题常常让人感到棘手。今天,我们将深入解析Java中的线程调度算法、调度策略,探讨线程调度器、时间分片的工作原理,并带你了解常见的线程同步方法。让我们一起破解这些面试难题,提升你的Java并发编程技能!
199 16
面试直击:并发编程三要素+线程安全全攻略!
并发编程三要素为原子性、可见性和有序性,确保多线程操作的一致性和安全性。Java 中通过 `synchronized`、`Lock`、`volatile`、原子类和线程安全集合等机制保障线程安全。掌握这些概念和工具,能有效解决并发问题,编写高效稳定的多线程程序。
186 11
硬核揭秘:线程与进程的底层原理,面试高分必备!
嘿,大家好!我是小米,29岁的技术爱好者。今天来聊聊线程和进程的区别。进程是操作系统中运行的程序实例,有独立内存空间;线程是进程内的最小执行单元,共享内存。创建进程开销大但更安全,线程轻量高效但易引发数据竞争。面试时可强调:进程是资源分配单位,线程是CPU调度单位。根据不同场景选择合适的并发模型,如高并发用线程池。希望这篇文章能帮你更好地理解并回答面试中的相关问题,祝你早日拿下心仪的offer!
123 6
Java 多线程 面试题
Java 多线程 相关基础面试题
【JavaEE】——单例模式引起的多线程安全问题:“饿汉/懒汉”模式,及解决思路和方法(面试高频)
单例模式下,“饿汉模式”,“懒汉模式”,单例模式下引起的线程安全问题,解锁思路和解决方法
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问