16.Java源码分析系列笔记-JDK1.7的ConcurrentHashMap

[复制链接]
发表于 2025-6-27 11:10:24 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
目录

1. 构造方法
  1. public ConcurrentHashMap() {
  2.         //16,0.75f,16
  3.     this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
  4. }
复制代码
2. put方法
  1. public V put(K key, V value) {
  2.     Segment<K,V> s;
  3.     //value不能为空
  4.     if (value == null)
  5.         throw new NullPointerException();
  6.     //计算key的hash值
  7.     int hash = hash(key);
  8.     //在用hash值计算j
  9.     int j = (hash >>> segmentShift) & segmentMask;
  10.     if ((s = (Segment<K,V>)UNSAFE.getObject          // nonvolatile; recheck
  11.          //用j计算地址,并且cas获取segment对象
  12.          (segments, (j << SSHIFT) + SBASE)) == null) //  in ensureSegment
  13.         //初始化
  14.         s = ensureSegment(j);
  15.     //调用segment的put方法
  16.     return s.put(key, hash, value, false);
  17. }
复制代码
2.2. ensureSegment
  1. private int hash(Object k) {
  2.     int h = hashSeed;
  3.     if ((0 != h) && (k instanceof String)) {
  4.         return sun.misc.Hashing.stringHash32((String) k);
  5.     }
  6.     h ^= k.hashCode();
  7.     // Spread bits to regularize both segment and index locations,
  8.     // using variant of single-word Wang/Jenkins hash.
  9.     h += (h <<  15) ^ 0xffffcd7d;
  10.     h ^= (h >>> 10);
  11.     h += (h <<   3);
  12.     h ^= (h >>>  6);
  13.     h += (h <<   2) + (h << 14);
  14.     return h ^ (h >>> 16);
  15. }
复制代码
2.3.1. scanAndLockForPut
  1. private Segment<K,V> ensureSegment(int k) {
  2.     final Segment<K,V>[] ss = this.segments;
  3.     long u = (k << SSHIFT) + SBASE; // raw offset
  4.     Segment<K,V> seg;
  5.     //segment为空,需要初始化。为什么使用cas而不是直接用下标???
  6.     if ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u)) == null) {
  7.             //原型模式,使用第一个segment作为原型
  8.         Segment<K,V> proto = ss[0]; // use segment 0 as prototype
  9.         //获取第一个segment的capacity,loadFactor,threshold,(后续用于创建entry table和segment)
  10.         int cap = proto.table.length;
  11.         float lf = proto.loadFactor;
  12.         int threshold = (int)(cap * lf);
  13.         
  14.         //创建entry table(后续用于创建segment)
  15.         HashEntry<K,V>[] tab = (HashEntry<K,V>[])new HashEntry[cap];
  16.         //重新确认为空,不为空说明已经有其他线程初始化了,直接退出,避免进入死循环+cas浪费cpu
  17.         if ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u))
  18.             == null) { // recheck
  19.             //创建segment
  20.             Segment<K,V> s = new Segment<K,V>(lf, threshold, tab);
  21.             //死循环+cas设置segment
  22.             while ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u))
  23.                    == null) {
  24.                 if (UNSAFE.compareAndSwapObject(ss, u, null, seg = s))
  25.                     break;
  26.             }
  27.         }
  28.     }
  29.     return seg;
  30. }
复制代码
2.3.2. rehash

[code]private void rehash(HashEntry node) {        /*         * Reclassify nodes in each list to new table.  Because we         * are using power-of-two expansion, the elements from         * each bin must either stay at same index, or move with a         * power of two offset. We eliminate unnecessary node         * creation by catching cases where old nodes can be         * reused because their next fields won't change.         * Statistically, at the default threshold, only about         * one-sixth of them need cloning when a table         * doubles. The nodes they replace will be garbage         * collectable as soon as they are no longer referenced by         * any reader thread that may be in the midst of         * concurrently traversing table. Entry accesses use plain         * array indexing because they are followed by volatile         * table write.         */        HashEntry[] oldTable = table;        int oldCapacity = oldTable.length;        //新的容量为旧容量*2        int newCapacity = oldCapacity >> segmentShift) & segmentMask) > segmentShift) & segmentMask) > segmentShift) & segmentMask)
回复

使用道具 举报

×
登录参与点评抽奖,加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表