I'm reading the source code of ConcurrentHashMap
in JDK8, notice that TreeBin
uses a 'read-write' lock to prevent concurrent read and write.
Read threads will go through TreeNodes if there's no concurrent write thread trying to modify the tree structure. When the 'find' operation is done, read thread may:
(1)'CAS' the lockState
and 'unpark' the waiter(writer) thread if it exists.
Following is the 'find()' method in source code.
final Node<K,V> find(int h, Object k) {
if (k != null) {
for (Node<K,V> e = first; e != null; ) {
int s; K ek;
if (((s = lockState) & (WAITER|WRITER)) != 0) {
if (e.hash == h &&
((ek = e.key) == k || (ek != null && k.equals(ek))))
return e;
e = e.next;
}
else if (U.compareAndSwapInt(this, LOCKSTATE, s,
s + READER)) {
TreeNode<K,V> r, p;
try {
p = ((r = root) == null ? null :
r.findTreeNode(h, k, null));
} finally {
Thread w;
// (1)if no more readers, try to unpark the waiter if it exists
if (U.getAndAddInt(this, LOCKSTATE, -READER) ==
(READER|WAITER) && (w = waiter) != null)
LockSupport.unpark(w);
}
return p;
}
}
}
return null;
}
on the other hand, writer thread may:
(2) adding the
WAITER
state tolockState
with 'CAS' operation.(3) set itself to
waiter
variable.(4) 'park' itself.
here's the writer's code:
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);
}
}
HERE IS MY CONFUSION:
If the four operation above run in this order (2) (1) (3) (4), the operation (1) won't unpark anything because 'waiter' was null at that moment.
Then the waiter will park forever without anyone who can unpark it.
The subsequent writes will be all blocked on the intrinsic lock held by the 'parked' thread.
IS THIS A CHANCE OF DEADLOCK ?
I'm really confused about this. I think perhaps I've missed something in the source code. Need your help if you are familiar with it.
find
:if (((s = lockState) & (WAITER|WRITER)) != 0)
? Why there is no synchronization here and in its block? – user2956272