请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

1.7版本concurrenthashmap保证并发可见性的疑惑

//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.putOrderedObjectUNSAFE.putObjectVolatile的区别是后者能保证可见性,前者是不能的。那这样1.7版本concurrenthashmap是怎么保证可见性的呢?比如,线程1remove操作修改了table[i]的链表头节点,指向了原链表的第二个hashentry对象。线程2紧接着进行get操作,读取这个table[i]的链表头节点。在这种场景下怎么保证线程2读取到的是remove过后的链表头节点(即原链表的第二个hashentry节点)。
这里我查阅了很多资料和帖子我都找不到我想要的答案,突然怀疑了自己对JMM理解的知识体系。。。。恳请悟空老师务必详细解答一下我的疑问

正在回答 回答被采纳积分+3

1回答

悟空 2020-03-24 02:16:38

remove后会解锁,由此具备了可见性,你可以看一下我第一门实战课讲过happens-before原理。

1 回复 有任何疑惑可以回复我~
  • 提问者 慕沐3053333 #1
    我不认同你的回答。concurrenthashmap1.7版本虽然remove过程会加锁解锁,但是get过程是没有锁的。和happens-before没有任何关系。
    回复 有任何疑惑可以回复我~ 2020-03-24 09:16:11
  • 悟空 回复 提问者 慕沐3053333 #2
    get取的时候会调用UNSAFE.getObjectVolatile,保证可见性。
    回复 有任何疑惑可以回复我~ 2020-03-24 10:09:25
  • 提问者 慕沐3053333 回复 悟空 #3
    可是remove操作最终调用的UNSAFE.putOrderedObject并没有像UNSAFE.putObjectVolatile那样立刻把工作内存的值刷回共享内存呀。此时尽管调用getObjectVolatile把共享内存的值刷回到工作内存,但是共享内存的值并不是最新的呀。
    回复 有任何疑惑可以回复我~ 2020-03-24 10:15:37
问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信