8132306: java/lang/ref/ReferenceEnqueue.java fails with "RuntimeException: Error: poll() returned null; expected ref object"
Summary: Carefully order ref.queue and queue list updates to address races.
Reviewed-by: dholmes, dfuchs, plevart
--- a/jdk/src/java.base/share/classes/java/lang/ref/ReferenceQueue.java Tue Aug 04 15:16:23 2015 +0200
+++ b/jdk/src/java.base/share/classes/java/lang/ref/ReferenceQueue.java Tue Aug 04 17:26:14 2015 -0400
@@ -65,10 +65,13 @@
return false;
}
assert queue == this;
- r.queue = ENQUEUED;
r.next = (head == null) ? r : head;
head = r;
queueLength++;
+ // Update r.queue *after* adding to list, to avoid race
+ // with concurrent enqueued checks and fast-path poll().
+ // Volatiles ensure ordering.
+ r.queue = ENQUEUED;
if (r instanceof FinalReference) {
sun.misc.VM.addFinalRefCount(1);
}
@@ -80,10 +83,13 @@
private Reference<? extends T> reallyPoll() { /* Must hold lock */
Reference<? extends T> r = head;
if (r != null) {
+ r.queue = NULL;
+ // Update r.queue *before* removing from list, to avoid
+ // race with concurrent enqueued checks and fast-path
+ // poll(). Volatiles ensure ordering.
@SuppressWarnings("unchecked")
Reference<? extends T> rn = r.next;
head = (rn == r) ? null : rn;
- r.queue = NULL;
r.next = r;
queueLength--;
if (r instanceof FinalReference) {
--- a/jdk/test/java/lang/ref/ReferenceEnqueue.java Tue Aug 04 15:16:23 2015 +0200
+++ b/jdk/test/java/lang/ref/ReferenceEnqueue.java Tue Aug 04 17:26:14 2015 -0400
@@ -22,7 +22,7 @@
*/
/* @test
- * @bug 4268317
+ * @bug 4268317 8132306
* @summary Test if Reference.enqueue() works properly with GC
*/