1.7版本concurrenthashmap保证并发可见性的疑惑
来源:9-12 相关结构图

慕沐3053333
2020-03-23
//segment的定义
static final class Segment<K,V> extends ReentrantLock implements Serializable {
...忽略...
transient volatile HashEntry<K,V>[] table;
...忽略...
}
//concurrenthashmap改变segment中hashentry数组中某一下标处的hashentry对象
/**
* Sets the ith element of given table, with volatile write
* semantics. (See above about use of putOrderedObject.)
*/
static final <K,V> void setEntryAt(HashEntry<K,V>[] tab, int i,
HashEntry<K,V> e) {
UNSAFE.putOrderedObject(tab, ((long)i << TSHIFT) + TBASE, e);
}
在remove操作中,当移除链表头节点时,会执行这段代码if (pred == null) setEntryAt(tab, index, next);
这个方法里面又会调用UNSAFE.putOrderedObject(tab, ((long)i << TSHIFT) + TBASE, e);
,从而改变hashentry数组对应下标的hashentry对象。
我查阅资料:UNSAFE.putOrderedObject
和UNSAFE.putObjectVolatile
的区别是后者能保证可见性,前者是不能的。那这样1.7版本concurrenthashmap是怎么保证可见性的呢?比如,线程1remove操作修改了table[i]的链表头节点,指向了原链表的第二个hashentry对象。线程2紧接着进行get操作,读取这个table[i]的链表头节点。在这种场景下怎么保证线程2读取到的是remove过后的链表头节点(即原链表的第二个hashentry节点)。
这里我查阅了很多资料和帖子我都找不到我想要的答案,突然怀疑了自己对JMM理解的知识体系。。。。恳请悟空老师务必详细解答一下我的疑问
写回答
1回答
-
悟空
2020-03-24
remove后会解锁,由此具备了可见性,你可以看一下我第一门实战课讲过happens-before原理。
132020-03-24
相似问题
原子类保证可见性吗?
回答 1
关于多线程修改布尔值的疑问
回答 1