JDK1.8 ConcurrentHashMap源码阅读
1.? 带着问题去阅读 为什么说ConcurrentHashMap是线程安全的?或者说?ConcurrentHashMap是如何防止并发的? 2.? 字段和常量 首先,来看一下ConcurrentHashMap中的一些字段和常量,这些在接下来的操作中会用得到 2.1.? 常量 从中,我们可以获得以下信息:
2.2.? 字段 从这些字段中,我们可以获得以下信息:
2.3.? 内部类 对比1.7里面的HashMap不难发现:
可以看到,TreeNode继承自Node,主要用于树形结构中。也就是说,TreeNode表示树中的结点。 还有一个TreeBin也是继承自Node TreeBin表示整个树,TreeNode表示树中的结点 正常情况下,数组中某个位置的元素应该是Node,而Node是一个链表,它后面可能跟了多个Node。 但是,某个位置的节点个数超过阈值(默认8)时,将这个链表转成红黑树,那么此后数组中这个位置的元素就是TreeBin 也就是说,Node表示链表中的节点,TreeNode表示树中的节点,TreeBin表示树 3.? 操作 3.1.? put 这里,再多看一眼,刚才的putTreeVal()方法 总的来说,是先插入,后调整 大致流程是这样的:
3.2.? resize 在上一步的put操作中,如果数组正在扩容,则帮助扩容 下面看一下扩容 我以前在理解上一直有一个误区,以前我一直以为在数组相同位置上的元素的哈希值都相同,今天我恍然大悟,原来不是这样的,这些元素之所以会在同一个位置是因为通过key的哈希值再结合数组长度计算得出该元素应该在这个位置上,而不同的哈希值可能经过计算也在同一个位置,所以,相同位置的元素的hash值不一定相同,或者说,链表上的元素的hash并不一定都相同,只是恰巧它们在数组的位置相同而已。 扩容是这样的:
下面是一个示意图,不必拘泥细节,重在意思 3.3.? get和remove 删除和获取相对比较简单,不再赘述 ? 至此,可以回答开头我们提出的问题了 sychronized +?volatile + CAS 插入、删除、扩容的时候都对数组中相应位置的元素加锁了,加锁用的是synchronized table数组、Node中的val和next、以及一些控制字段都加了volatile 在更新一些关键变量的时候用到了sun.misc.Unsafe中的一些方法 ? (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |