ConcurrentHashMap remove() 在使用线程 B 迭代时使用线程 A
ConcurrentHashMap remove() using thread A while iterating using thread B
据我了解,put()
、clear()
和 remove()
是由 ConcurrentHashMap
提供的,它是线程安全操作,无需使用任何锁。
在ConcurrentHashMap
中,有不同的段,每个段有几个散列桶。
Clear()
和 put()
是线程安全的,因为 clear()
只是清除了对该桶的哈希链的引用,但哈希链仍然存在,所以如果 thread A 正在迭代它,它不会受到影响,但 thread B 的 clear()
。 Put()
总是会在该桶的哈希链的开头放置一个新节点,所以也可以。
但是,我不明白的是为什么remove()
会是线程安全的?比如hash bucket是bucket->A->B->C->D->E并且线程A调用remove(C)
,ConcurrentHashMap
实现提供的机制是将A,B复制到下一个链表中,但顺序相反bucket->B->A->D-E 然后将 A.next 变成原来的 D->E,结果是 bucket->B->A->D-E。
为什么这是线程安全的?如果 thread B
当前正在遍历元素 A 然后 thread A
调用 remove(C) 怎么办?好像要坏了?
嗯,remove() 克隆 HashEntry 元素直到删除的元素,而不是修改旧元素。所以你得到
B*->A*->D->E 在桶中,但原始
A->B->C-^序列未触及
您可以确定 A.equals(A*) == false,即使它们具有相同的键和值。但这对迭代器来说不是问题,因为它只是使用已经获取的条目 A 继续前进。
P.S。 ConcurrentHashMap 使用桶级别的锁进行修改。它不是无锁的。
据我了解,put()
、clear()
和 remove()
是由 ConcurrentHashMap
提供的,它是线程安全操作,无需使用任何锁。
在ConcurrentHashMap
中,有不同的段,每个段有几个散列桶。
Clear()
和 put()
是线程安全的,因为 clear()
只是清除了对该桶的哈希链的引用,但哈希链仍然存在,所以如果 thread A 正在迭代它,它不会受到影响,但 thread B 的 clear()
。 Put()
总是会在该桶的哈希链的开头放置一个新节点,所以也可以。
但是,我不明白的是为什么remove()
会是线程安全的?比如hash bucket是bucket->A->B->C->D->E并且线程A调用remove(C)
,ConcurrentHashMap
实现提供的机制是将A,B复制到下一个链表中,但顺序相反bucket->B->A->D-E 然后将 A.next 变成原来的 D->E,结果是 bucket->B->A->D-E。
为什么这是线程安全的?如果 thread B
当前正在遍历元素 A 然后 thread A
调用 remove(C) 怎么办?好像要坏了?
嗯,remove() 克隆 HashEntry 元素直到删除的元素,而不是修改旧元素。所以你得到
B*->A*->D->E 在桶中,但原始
A->B->C-^序列未触及
您可以确定 A.equals(A*) == false,即使它们具有相同的键和值。但这对迭代器来说不是问题,因为它只是使用已经获取的条目 A 继续前进。
P.S。 ConcurrentHashMap 使用桶级别的锁进行修改。它不是无锁的。