296 |
|
* Removes and signals all waiting threads, and invokes done(). |
297 |
|
*/ |
298 |
|
private void finishCompletion() { |
299 |
< |
WaitNode q; |
300 |
< |
while ((q = waiters) != null) { |
299 |
> |
for (WaitNode q; (q = waiters) != null;) { |
300 |
|
if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) { |
301 |
|
for (;;) { |
302 |
|
Thread t = q.thread; |
363 |
|
* Tries to unlink a timed-out or interrupted wait node to avoid |
364 |
|
* accumulating garbage. Internal nodes are simply unspliced |
365 |
|
* without CAS since it is harmless if they are traversed anyway |
366 |
< |
* by releasers. To avoid effects of unsplicing from already |
367 |
< |
* removed nodes, the list is retraversed until no cancelled nodes |
368 |
< |
* are found. This is slow when there are a lot of nodes, but we |
369 |
< |
* don't expect lists to be long enough to outweigh |
370 |
< |
* higher-overhead schemes. |
366 |
> |
* by releasers. To avoid effects of unsplicing from already |
367 |
> |
* removed nodes, the list is retraversed in case of an apparent |
368 |
> |
* race. This is slow when there are a lot of nodes, but we don't |
369 |
> |
* expect lists to be long enough to outweigh higher-overhead |
370 |
> |
* schemes. |
371 |
|
*/ |
372 |
|
private void removeWaiter(WaitNode node) { |
373 |
|
if (node != null) { |
374 |
|
node.thread = null; |
375 |
< |
for (WaitNode pred = null, q = waiters; q != null;) { |
376 |
< |
WaitNode next = q.next; |
377 |
< |
if (q.thread != null) { |
378 |
< |
pred = q; |
379 |
< |
q = next; |
380 |
< |
} |
381 |
< |
else { |
382 |
< |
if (pred != null) |
383 |
< |
pred.next = next; |
384 |
< |
else |
385 |
< |
UNSAFE.compareAndSwapObject(this, waitersOffset, |
386 |
< |
q, next); |
387 |
< |
pred = null; // restart until clean sweep |
388 |
< |
q = waiters; |
375 |
> |
retry: |
376 |
> |
for (;;) { // restart on removeWaiter race |
377 |
> |
for (WaitNode pred = null, q = waiters, s; q != null; q = s) { |
378 |
> |
s = q.next; |
379 |
> |
if (q.thread != null) |
380 |
> |
pred = q; |
381 |
> |
else if (pred != null) { |
382 |
> |
pred.next = s; |
383 |
> |
if (pred.thread == null) // check for race |
384 |
> |
continue retry; |
385 |
> |
} |
386 |
> |
else if (!UNSAFE.compareAndSwapObject(this, waitersOffset, |
387 |
> |
q, s)) |
388 |
> |
continue retry; |
389 |
|
} |
390 |
+ |
break; |
391 |
|
} |
392 |
|
} |
393 |
|
} |