再来一篇!看jdk源码大师亲自操刀编写的集合源码!

全文共计1959字18图,预计阅读时间13分钟
大家好,我是tin,这是我的第8篇原创文章

再来一篇!看jdk源码大师亲自操刀编写的集合源码!
文章图片
?
这个图拍摄于老家县城一售楼处。作为外出上班的一族,一年365天在家的时间常常不超过十天。
在侃技术前,聊一聊自己对家乡变化的感慨。
最大的感慨莫过于,我们县城要通高铁了,以后老家和工作之地的距离将变成2小时!想想就觉得这是一件多么幸福的事。
今年过年回家趁着假期和家人又新购置了一套新商品期房,就买高铁站片区边上。
再来一篇!看jdk源码大师亲自操刀编写的集合源码!
文章图片
?
在家买房的最大特点就是,房子面积要大的,动不动都一百多两百平,在深圳这个地方就不敢想啦。
房子本来最早于2019年已打算购置,但当时时间仓促没看好,加之2020年过年刚好遇上疫情,足不出户,一耽搁就到了2021年。
或许刚好是疫情的原因,今年房价特价销售(也就是降价了),相对2019年降了500-1000元/㎡。在这种七八线城市,房价本就几千块一平,这个降价幅度是异常高的(打心里认为,2021年是小城购房最佳时机之一)。
其实,这里唠嗑只是想感慨一下小城市的变化之大!但是我们很多人却容易忽略身边最亲近的事与物。比如我,我竟然不知我们县城的政务中心都搬迁了,整个县城南片区规划建设已相当完善,商品房、幼儿园、中小学校区、超宽大道等等随处可见,新医院、新行政办公楼、高铁站等这些似乎在缩小与大城市的差距。
这些年,国家对农村建设力度也很大,肉眼可见的变化常常被我们谈及。普遍被提到的一个变化是路变好了。村村通公路、水泥路,每年外出回家的人一定能感受到。路变好,相应的是,车也就多了。买车的人越来越多,每家都会有一辆代步小轿车。
除了车,家里爸爸妈妈们网上购物更加频繁,比起以往,老人们都可以自行网上购物,自行取快递,这种线上体验的场景规模越来越空大,所以,农村通宽带也已不是什么新鲜事。
朋友们,你们觉得呢,你们家乡还有哪些变化?
ConcurrentHashMap 我们打开ConcurrentHashMap源码,类开头鲜明地标着作者: @author Doug Lea
再来一篇!看jdk源码大师亲自操刀编写的集合源码!
文章图片
?
Doug Lea是谁?以前也有提到过,他是一位大学老师,同时也是世界上对Java影响最大的人之一。JDK源码中java.util.concurrent 包就是他创作的。
再来一篇!看jdk源码大师亲自操刀编写的集合源码!
文章图片
?
【再来一篇!看jdk源码大师亲自操刀编写的集合源码!】再来一篇!看jdk源码大师亲自操刀编写的集合源码!
文章图片

我们找到jdk1.7的源码,ConcurrentHashMap中的get方法还能看到Doug Lea的代码(下图源码截图基于jdk7-b147)
再来一篇!看jdk源码大师亲自操刀编写的集合源码!
文章图片
?
我们知道,HashMap 是线程不安全的,并发情况下使用hashmap有cpu飙升的风险。为了使用线程安全的 HashMap,我们常使用 ConcurrentHashMap。
本文基于jdk1.7讲解,所以concurrenthashmap还是采用分段锁。
再来一篇!看jdk源码大师亲自操刀编写的集合源码!
文章图片
?
再来一篇!看jdk源码大师亲自操刀编写的集合源码!
文章图片

ConcurrentHashmap默认有16个Segment,最多支持65536个Segment,这是可以通过ConcurrentHashMap的构造器指定的。默认情况下ConcurrencyLevel等于16
再来一篇!看jdk源码大师亲自操刀编写的集合源码!
文章图片
?
再来一篇!看jdk源码大师亲自操刀编写的集合源码!
文章图片

如果指定ConcurrencyLevel,最大只能等于65535
再来一篇!看jdk源码大师亲自操刀编写的集合源码!
文章图片
?
再来一篇!看jdk源码大师亲自操刀编写的集合源码!
文章图片

Segment通过继承ReentrantLock来进行加锁,每次锁住一个segment来保证每个Segment内的操作的线程安全性从而实现全局线程安全。
定位一个元素的过程需要进行两次Hash操作,第一次Hash定位到Segment,第二次Hash定位到元素所在的链表的头部。看看get方法的源码:
再来一篇!看jdk源码大师亲自操刀编写的集合源码!
文章图片
?
再来一篇!看jdk源码大师亲自操刀编写的集合源码!
文章图片

ConcurrentHashMap定义了一个Segment数组segments,Segment则定义了一个HashEntry数组table。
这种两级定位的结构带来的副作用是hash过程要比普通的HashMap要长,但是带来的好处是更大的,写操作可以只对元素所在的Segment进行加锁即可,不会影响到其他的Segment,这样,ConcurrentHashMap可以支持最大Segment数量的并发量,吞吐量就比HashMap大了很多。
细心的你可能已经发现,代码截图中使用到了UNSAFE.getObjectVolatile(segments, u) ,这个是什么意思呢?
getObjectVolatile是为保证并发访问数组的第 k 个元素可以显式 volatile 读取,为了值的可见性。
说到Unsafe,这玩意儿咋一看感觉很高大上,因为我们平常编程几乎没见过。但是,Unsafe现在在Java里面是一个“擦边球”,基本处于一个“不推荐使用”的状态。
Unsafe是位于sun.misc包下的一个类,主要提供一些用于执行低级别、不安全操作的方法,如直接访问系统内存资源、自主管理内存资源等。因为可以访问系统资源、可以自主操作内存空间,这无疑增加了程序发生指针问题的风险,Java的垃圾回收器本来很大一个原因是为了解决这个问题,使用Unsafe类会使得程序出错的概率变大,Java官方也不建议开发者使用它。
R大有一篇回答,关于Unsafe,为什么JUC中大量使用了sun.misc.Unsafe 这个类,但官方却不建议开发者使用? - 知乎
结语 我是tin,一个在努力让自己变得更优秀的普通攻城狮。自己阅历有限、学识浅薄,如有发现文章不妥之处,非常欢迎加我提出,我一定细心推敲加以修改。
坚持原创不容易,你的正反馈是我坚持输出的最强大动力,谢谢!

    推荐阅读