关于ConcurrentHashMap的一个疑问

inCoding 2013-05-27 05:12:22
最近学习了一下CouncurrentHashMap的源码 突然有个疑问
rehash
void rehash() {
HashEntry<K,V>[] oldTable = table;
int oldCapacity = oldTable.length;
if (oldCapacity >= MAXIMUM_CAPACITY)
return;

/*
* Reclassify nodes in each list to new Map. Because we are
* using power-of-two expansion, the elements from each bin
* must either stay at same index, or move with a power of two
* offset. We eliminate unnecessary node creation by catching
* cases where old nodes can be reused because their next
* fields won't change. Statistically, at the default
* threshold, only about one-sixth of them need cloning when
* a table doubles. The nodes they replace will be garbage
* collectable as soon as they are no longer referenced by any
* reader thread that may be in the midst of traversing table
* right now.
*/

HashEntry<K,V>[] newTable = HashEntry.newArray(oldCapacity<<1);
threshold = (int)(newTable.length * loadFactor);
int sizeMask = newTable.length - 1;
for (int i = 0; i < oldCapacity ; i++) {
// We need to guarantee that any existing reads of old Map can
// proceed. So we cannot yet null out each bin.
HashEntry<K,V> e = oldTable[i];

if (e != null) {
HashEntry<K,V> next = e.next;
int idx = e.hash & sizeMask;

// Single node on list
if (next == null)
newTable[idx] = e;

else {
// Reuse trailing consecutive sequence at same slot
HashEntry<K,V> lastRun = e;
int lastIdx = idx;
for (HashEntry<K,V> last = next;
last != null;
last = last.next) {
int k = last.hash & sizeMask;
if (k != lastIdx) {
lastIdx = k;
lastRun = last;
}
}
newTable[lastIdx] = lastRun;

// Clone all remaining nodes
for (HashEntry<K,V> p = e; p != lastRun; p = p.next) {
int k = p.hash & sizeMask;
HashEntry<K,V> n = newTable[k];
newTable[k] = new HashEntry<K,V>(p.key, p.hash,
n, p.value);
}
}
}
}
table = newTable;
}

我发现在代码执行开始
HashEntry<K,V>[] oldTable = table; 获取了最新的table(table是volatile的)
代码执行过程并未加锁,那么在高并发环境下,在rehash时势必会丢失一些值,不知道我理解的对不对,哪位高手能详细的解释下。


...全文
124 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
oh_Maxy 2013-05-28
  • 打赏
  • 举报
回复
引用 4 楼 wxhduanxian 的回复:
[quote=引用 2 楼 oh_Maxy 的回复:] 之前也看过这个类的,除了那个volatile关键字外,LZ可以看看它的put或remove操作的实现,往里跟,在内部类Segment<K, V>有个lock();操作的,这就解决了高并发的问题了。
put 和 remove确实有锁,实现我也看了,这里说的rehash确实没有加锁。volatile只能保证 HashEntry<K,V>[] oldTable = table; 这句时得到的table是最新的。但是后续程序执行都是通过中间变量oldTable去做的。rehash确实没看到锁。[/quote] 这是我看到的源码: V put(K key, int hash, V value, boolean onlyIfAbsent) { lock(); try { int c = count; if (c++ > threshold) // ensure capacity rehash(); ... lock操作是在最前面的,这个应该能满足了吧?
inCoding 2013-05-28
  • 打赏
  • 举报
回复
抱歉,从put中进行rehash()时候确实加了锁。没看到结帖子了!
inCoding 2013-05-28
  • 打赏
  • 举报
回复
引用 3 楼 fei1710 的回复:
rehash怎么会不加锁呢?增删改操作都是加锁了的。 首先会尝试tryLock,如果失败,再调用scanAndLock,返回的时候已经加锁了。
你可以现在看下源码。 rehash确实没有锁
inCoding 2013-05-28
  • 打赏
  • 举报
回复
引用 2 楼 oh_Maxy 的回复:
之前也看过这个类的,除了那个volatile关键字外,LZ可以看看它的put或remove操作的实现,往里跟,在内部类Segment<K, V>有个lock();操作的,这就解决了高并发的问题了。
put 和 remove确实有锁,实现我也看了,这里说的rehash确实没有加锁。volatile只能保证 HashEntry<K,V>[] oldTable = table; 这句时得到的table是最新的。但是后续程序执行都是通过中间变量oldTable去做的。rehash确实没看到锁。
fei1710 2013-05-27
  • 打赏
  • 举报
回复
rehash怎么会不加锁呢?增删改操作都是加锁了的。 首先会尝试tryLock,如果失败,再调用scanAndLock,返回的时候已经加锁了。
oh_Maxy 2013-05-27
  • 打赏
  • 举报
回复
之前也看过这个类的,除了那个volatile关键字外,LZ可以看看它的put或remove操作的实现,往里跟,在内部类Segment<K, V>有个lock();操作的,这就解决了高并发的问题了。
inCoding 2013-05-27
  • 打赏
  • 举报
回复
没人回复吗,自己顶一个

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧