前言

最近在看dubbo源码的时候,突然发现一个有趣的事情,dubbo有一小部分代码是原封不动的抄袭Netty代码。直接上图:
dubbo源码:
image.png
Netty源码:
image.png

可以看到,Dubbo只是改了个类名(FastThreadLocal -> InternalThreadLocal),连注释都照搬过来了!并美其名曰“借鉴”Netty的设计思路。确实,代码人的事情怎么能叫抄袭呢?嘿嘿。

正题

不过话说回来,虽然是抄袭,但也正说明了Netty的FastThreadLocal设计思路非常好,才会让Dubbo的开发者将它也引入了Dubbo内部。下面我们就来看看FastThreadLocal的设计思路和实现原理吧。

设计思路

image.png

从注释上可以看到,FastThreadLocal采用数组下标的方式,代替了JDK原生的hash code + hash table的方式,虽然改动不大,但在频繁访问的场景下,也能提升性能。
它有个使用前提,那就是我们的线程Thread必须是FastThreadLocalThread的实现类或子类,因此Netty内部的默认ThreadFactory创建的都是FastThreadLocalThread类型,如果是其他Thread类型,会退化到JDK的ThreadLocal。

实现原理

(ps:胃病犯了,下次补充上,有兴趣的童鞋可以自己去翻看下,有耐心的童鞋可以点个关注,下次一定更新!对,下次一定!嘻嘻)

小插曲

另外我在看Dubbo的SPI部分源码时,还发现了一件有趣的事情,有位热心的开源贡献者给Dubbo提交了PR,说是JDK1.8的ConcurrentHashMap#computeIfAbsent()方法有bug,就把它换成了putIfAbsent(),并被Dubbo的commiter review通过并合入了。PR链接:https://github.com/apache/dub...

image.png

这位开源贡献者还把这个jdk官方bug的记录列表发出来了
https://bugs.openjdk.java.net...
image.png

带着好奇心,我也打开了这个bug链接,说的是如果在computeIfAbsent()方法里面递归调用computeIfAbsent()的话,有几率出现死循环bug,这个几率指的是哈希碰撞的时候。具体看bug描述吧:
image.png
image.png

死循环样例代码:
image.png

这个bug只有在递归调用的时候才有几率出现死循环,并且ConcurrentHashMap的作者Doug Lea大师,在JDK1.9版本的解决办法也只是在检测到递归调用的时候抛出异常,说明不推荐用户递归调用:

image.png
也就是说,只要我们不递归调用computeIfAbsent,就不会出现死循环bug,显然dubbo这里没有违反这条约定,自然不会出现死循环bug,挺好奇当时commiter是怎么review通过并merge的呢?

这两件事,让我体会到,哪怕是Dubbo这样知名的Apache顶级项目,也有这样那样的缺陷,说明大牛们也是人,不是神,也会犯错,这让我更加有自信,来参与到开源社区中了!


小强大人
34 声望4 粉丝