As code shown below in FutureTask.java
(Jdk1.7):
/**
* Tries to unlink a timed-out or interrupted wait node to avoid
* accumulating garbage. Internal nodes are simply unspliced
* without CAS since it is harmless if they are traversed anyway
* by releasers. To avoid effects of unsplicing from already
* removed nodes, the list is retraversed in case of an apparent
* race. This is slow when there are a lot of nodes, but we don't
* expect lists to be long enough to outweigh higher-overhead
* schemes.
*/
private void removeWaiter(WaitNode node) {
if (node != null) {
node.thread = null;
retry:
for (;;) { // restart on removeWaiter race
for (WaitNode pred = null, q = waiters, s; q != null; q = s) {
s = q.next;
if (q.thread != null)
pred = q;
else if (pred != null) {
pred.next = s;
if (pred.thread == null) // check for race
continue retry;
}
else if (!UNSAFE.compareAndSwapObject(this, waitersOffset,
q, s))
continue retry;
}
break;
}
}
}
We can find that there has two comments:
check for race
And
restart on removeWaiter race
This is a simple image that shown the state change in removeWaiter
:
There is my understanding and question:
Race condition: When a thread successfully finds the pred
node, and another thread try to remove pred
node, race happend.
In my opnion: q.next
,q.thread
and pred.thread
are both volitile
,so if current thread continue race with others threads, the result will also valid.
Question: Why Doug Lea choose restart race rather than continue race, or is there something wrong for my opinion?