该帖已经被评为良好帖
|
|
---|---|
作者 | 正文 |
发表时间:2009-03-13
ConcurrentHashMap 不是绝对线程安全的.
谁举个ConcurrentHashMap的最佳应用场景呢? |
|
返回顶楼 | |
发表时间:2009-03-13
marlonyao 写道
dlovek 写道
marlonyao 写道 其实这种方式是存在问题的,在第一个内层for循环中,在这两条语句sum += segments[i].count; mcsum += mc[i] = segments[i].modCount;之间,其它线程可能正在对Segment进行结构性的修改,导致segments[i].count和segments[i].modCount读取的数据并不一致。这可能使size()方法返回任何时候都不曾存在的大小,很奇怪javadoc居然没有明确标出这一点,可能是因为这个时间窗口太小了吧。size()的实现还有一点需要注意,必须要先segments[i].count,才能segments[i].modCount,这是因为segment[i].count是对volatile变量的访问,接下来segments[i].modCount才能得到几乎最新的值(前面我已经说了为什么只是“几乎”了)。 楼主写的非常好,又使我明白的不少东西。这个地方还是不理解,为什么需要首先调用一次volatile变量才使的modCount几乎可以得到最新的值? 写volatile变量和它之前的读写操作是不能reorder的,读volatile变量和它之后的读写操作也是不能reorder的。 修改modCount发生在修改count之前,由于count是volatile变量,修改modCount不能和写count的操作reorder,读取count和它之后的操作,比如读取modCount,不能reorder。有了这两个不能reorder才能保证读取了count之后,能读到线程在写count之前的写入的modCount值,这个modCount值是几乎最新的。 如果在读modCount之前不读count,读modCount甚至可能会reorder到写modCount之前。 用reorder解释总是太复杂了,不如用happens-before来得简洁。当一个线程I对count的读时,它读到的值必定是另一个线程,假设是线程II,最近对count的写。这个两个操作存在happens-before关系,即线程II对count的写happens-before线程I对count的读,记作:II:W(count) < I:R(count)。单线程的happens-before规则,又有II:W(modCount) < II:W(count)(查看源代码会发现在写count之前必定有写modCount),以及 I:R(count) < I:R(modCount),根据传递规则有,II:W(modCount) < I:R(modCount),这就是说线程I至少能够读取到线程II写count之前的modCount值。我曾经写了一篇关于happens-before的文章,有些表达可能有误,但大致还是对的,http://www.iteye.com/topic/260515。 不理解的话,也只能告诉你结论了,如果没有对count的写的话(对volatile的写是一种同步操作),读modCount可能读到很久很久很久以前的值(初始值0都有可能)。 期待高人做更简洁的解释吧。 看了半天才看明白,不知道修改的对不对? |
|
返回顶楼 | |
发表时间:2009-03-13
holan 写道
为什么删除的时候要吧原来的节点复制一次,不能直接删除吗?
因为next属性为final的,不可以被重置。直接删除,就无法保持链结果的连续性了。 |
|
返回顶楼 | |
发表时间:2009-04-17
e 是什么事件呀
|
|
返回顶楼 | |
发表时间:2009-05-03
最后修改:2009-05-03
marlonyao 写道 mercyblitz 写道 marlonyao 写道 dlovek 写道 恩,我有看到在Segment的删除/添加方法都是先修改了modCount然后修改了volatile的count值。
在containsValue方法中,“内层的第一个for循环,里面有语句int c = segments[i].count; 但是c却从来没有被使用过,即使如此,编译器也不能做优化将这条语句去掉,因为存在对volatile变量count的读取,这条语句存在的唯一目的就是保证segments[i].modCount读取到几乎最新的值”,这个就不理解了。 见我前面的回复,如果不先读count,就有可能读到modCount很久以前的陈旧值。 volatile 不能100%保证读到的是最新的数值,也可说volatile是轻量级别的sychronized。 volatile保证100%读取到最新的数据,对这里来说,它保证100%读取到count的最新值,但是对非volatile变量就不一样了。 volatile在高并发的情况下是不能保证的,它能保证HB的关系,但是HB不能保证是最新的值,必须通过synchronized关键字或者Lock机制来保证从主存中获取最近的数值,volatile只是不让数值保存在寄存器来中,并不是完全真实主存的值,可能是Thread stack中一个比较新的数值。 |
|
返回顶楼 | |
发表时间:2009-05-03
iamjxc 写道 ConcurrentHashMap 不是绝对线程安全的.
谁举个ConcurrentHashMap的最佳应用场景呢? 应该没有最佳之说,只能说在性能和数据一致性方面,它可能是比较好的一个途径。 如果要可靠的话,还是要使用Collections.synchronizedMap(Map map)方法,利用的synchronized机制,保证数据的一致性,然而ConcurrentHashMap只是保证Happens-before关系。 |
|
返回顶楼 | |