是否有可能与两个线程 lockRoot 的 ConcurrentHashMap 发生死锁
Is it possible to get a deadlock with ConcurrentHashMap with two threads lockRoot
如果两个线程同时将 vals 放入一棵树中
private final void contendedLock() {
boolean waiting = false;
for (int s;;) {
if (((s = lockState) & ~WAITER) == 0) {
if (U.compareAndSwapInt(this, LOCKSTATE, s, WRITER)) {
if (waiting)
waiter = null;
return;
}
}
else if ((s & WAITER) == 0) {
if (U.compareAndSwapInt(this, LOCKSTATE, s, s | WAITER)) {
waiting = true;
waiter = Thread.currentThread();
}
}
else if (waiting)
LockSupport.park(this);
}
}
Thread1:CAS 锁定状态到 WRITER
Thread2:CAS 锁定状态到 (WRITER|WAITER)
线程 2:LockSupport.park(这个)
线程 1:unlockRoot
private final void unlockRoot() {
lockState = 0;
}
那谁能解开 Thread2?
find() 方法的最后一部分需要在严格的条件下完成
finally {
Thread w;
if (U.getAndAddInt(this, LOCKSTATE, -READER) ==
(READER|WAITER) && (w = waiter) != null)
LockSupport.unpark(w);
}
谁能告诉我我是不是想错了?
您的推理是基于这样的假设,即 2 个写入线程可能会进入 contendedLock()
方法,而第二个写入线程将自行无限期停放,这当然是不可能的,因为 putVal
是相关树的 synchronized on the root node。
事实上,lockState
仅用于通过 CAS 编排 readers 与 writers,并且仅当 reader 和 writer 都尝试访问相同的 RB 树(即他们都对具有相同散列的密钥进行操作)。
在这种情况下,一旦发现 lockState=READER
,编写器线程就会自行停止(然后通过 OR (s | WAITER
) 将 WAITER
位添加到 lockState
中. 这个值 (00000110) 稍后将被 reader 在 finally
块中使用以取消停放写入线程(一旦它通过添加 -READER
清除读取状态,即 -4 , 并且看到之前的值也是 00000110)
如果两个线程同时将 vals 放入一棵树中
private final void contendedLock() {
boolean waiting = false;
for (int s;;) {
if (((s = lockState) & ~WAITER) == 0) {
if (U.compareAndSwapInt(this, LOCKSTATE, s, WRITER)) {
if (waiting)
waiter = null;
return;
}
}
else if ((s & WAITER) == 0) {
if (U.compareAndSwapInt(this, LOCKSTATE, s, s | WAITER)) {
waiting = true;
waiter = Thread.currentThread();
}
}
else if (waiting)
LockSupport.park(this);
}
}
Thread1:CAS 锁定状态到 WRITER
Thread2:CAS 锁定状态到 (WRITER|WAITER)
线程 2:LockSupport.park(这个)
线程 1:unlockRoot
private final void unlockRoot() {
lockState = 0;
}
那谁能解开 Thread2?
find() 方法的最后一部分需要在严格的条件下完成
finally {
Thread w;
if (U.getAndAddInt(this, LOCKSTATE, -READER) ==
(READER|WAITER) && (w = waiter) != null)
LockSupport.unpark(w);
}
谁能告诉我我是不是想错了?
您的推理是基于这样的假设,即 2 个写入线程可能会进入 contendedLock()
方法,而第二个写入线程将自行无限期停放,这当然是不可能的,因为 putVal
是相关树的 synchronized on the root node。
事实上,lockState
仅用于通过 CAS 编排 readers 与 writers,并且仅当 reader 和 writer 都尝试访问相同的 RB 树(即他们都对具有相同散列的密钥进行操作)。
在这种情况下,一旦发现 lockState=READER
,编写器线程就会自行停止(然后通过 OR (s | WAITER
) 将 WAITER
位添加到 lockState
中. 这个值 (00000110) 稍后将被 reader 在 finally
块中使用以取消停放写入线程(一旦它通过添加 -READER
清除读取状态,即 -4 , 并且看到之前的值也是 00000110)