马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
目录
1. 构造方法
- public ConcurrentHashMap() {
- //16,0.75f,16
- this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
- }
复制代码 2. put方法
- public V put(K key, V value) {
- Segment<K,V> s;
- //value不能为空
- if (value == null)
- throw new NullPointerException();
- //计算key的hash值
- int hash = hash(key);
- //在用hash值计算j
- int j = (hash >>> segmentShift) & segmentMask;
- if ((s = (Segment<K,V>)UNSAFE.getObject // nonvolatile; recheck
- //用j计算地址,并且cas获取segment对象
- (segments, (j << SSHIFT) + SBASE)) == null) // in ensureSegment
- //初始化
- s = ensureSegment(j);
- //调用segment的put方法
- return s.put(key, hash, value, false);
- }
复制代码 2.2. ensureSegment
- private int hash(Object k) {
- int h = hashSeed;
- if ((0 != h) && (k instanceof String)) {
- return sun.misc.Hashing.stringHash32((String) k);
- }
- h ^= k.hashCode();
- // Spread bits to regularize both segment and index locations,
- // using variant of single-word Wang/Jenkins hash.
- h += (h << 15) ^ 0xffffcd7d;
- h ^= (h >>> 10);
- h += (h << 3);
- h ^= (h >>> 6);
- h += (h << 2) + (h << 14);
- return h ^ (h >>> 16);
- }
复制代码 2.3.1. scanAndLockForPut
- private Segment<K,V> ensureSegment(int k) {
- final Segment<K,V>[] ss = this.segments;
- long u = (k << SSHIFT) + SBASE; // raw offset
- Segment<K,V> seg;
- //segment为空,需要初始化。为什么使用cas而不是直接用下标???
- if ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u)) == null) {
- //原型模式,使用第一个segment作为原型
- Segment<K,V> proto = ss[0]; // use segment 0 as prototype
- //获取第一个segment的capacity,loadFactor,threshold,(后续用于创建entry table和segment)
- int cap = proto.table.length;
- float lf = proto.loadFactor;
- int threshold = (int)(cap * lf);
-
- //创建entry table(后续用于创建segment)
- HashEntry<K,V>[] tab = (HashEntry<K,V>[])new HashEntry[cap];
- //重新确认为空,不为空说明已经有其他线程初始化了,直接退出,避免进入死循环+cas浪费cpu
- if ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u))
- == null) { // recheck
- //创建segment
- Segment<K,V> s = new Segment<K,V>(lf, threshold, tab);
- //死循环+cas设置segment
- while ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u))
- == null) {
- if (UNSAFE.compareAndSwapObject(ss, u, null, seg = s))
- break;
- }
- }
- }
- return seg;
- }
复制代码 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) |