Not quite. You are right that it should never be called. However, the JLS/JMM can be read as not absolutely forbidding it from being called because of weaknesses in required ordering relationships among finals vs volatiles set in constructors (key is final, value is volatile), wrt the reads by threads using the entry objects. (In JMM-ese, ordering constraints for finals fall outside of the synchronizes-with relation.) That's the issue the doc comment (pasted below) refers to. No one has ever thought of any practical loophole that a processor/compiler might find to produce a null value read, and it may be provable that none exist (and perhaps someday a JLS/JMM revision will fill in gaps to clarify this), but Bill Pugh once suggested we put this in anyway just for the sake of being conservatively pedantically correct. In retrospect, I'm not so sure this was a good idea, since it leads people to come up with exotic theories.
Get 操作并没有对底层的数组或者链表产生更改操作。楼主的疑问可能是Get的时候另一个线程同时put,或者get的时候另一个线程同时remove。其实这里没问题的 ,如果get在前put在后,那就get到null啦,如果get后remove在前,那也会拿到null啦。不会出现put在前反而get到null的情况或者remove再前反而拿到obj的情况。因为remove或者put最终的操作就是原子的设置 segment[i].table[j]. get操作没有机会对该操作捣乱
内部实现用了锁,你用它的时候就不需要再加一层锁了
2/3. 写入没完成的时候就读,就会读到null,此时锁是被写操作lock的,等待写操作unlock,再去读就可以读到了。
get
无需加锁,只是读取并不会对数据发生改变readValueUnderLock
正常情况不会被执行e.value
不会为null
作者Doug Lea
解释如下在高版本的jdk中
ConncurrentHashMap
已经完全重写了,这部分代码也没有了。ConncurrentHashMap 是jdk5引入的,它本身的操作就是保证了线程安全的,因此不需要加锁了
经典读写模型,读一般不用加锁的
Get 操作并没有对底层的数组或者链表产生更改操作。楼主的疑问可能是Get的时候另一个线程同时put,或者get的时候另一个线程同时remove。其实这里没问题的 ,如果get在前put在后,那就get到null啦,如果get后remove在前,那也会拿到null啦。不会出现put在前反而get到null的情况或者remove再前反而拿到obj的情况。因为remove或者put最终的操作就是原子的设置 segment[i].table[j]. get操作没有机会对该操作捣乱