FULL PRODUCT VERSION :
java version "1.6.0_01"
Java(TM) SE Runtime Environment (build 1.6.0_01-b06)
Java HotSpot(TM) Server VM (build 1.6.0_01-b06, mixed mode)
Problem also exists in JDK6 Mercurial repository http://hg.openjdk.java.net/jdk6/jdk6/jdk/summary as of changeset 135 a42d6999734b
ADDITIONAL OS VERSION INFORMATION :
Linux 2.6.24-gg23-generic #1 SMP Fri Jan 30 14:07:49 PST 2009 x86_64 GNU/Linux
A DESCRIPTION OF THE PROBLEM :
It is possible for a Reference.enqueue() call to return true twice on the same Reference instance.
The issue appears to be that ReferenceQueue.enqueue(Reference) does not check for
if (r.queue == NULL) return false;
Consequently what can happen is:
- some thread T1 enqueues the reference via Reference.enqueue().
- T1 calls ReferenceQueue.poll() and takes the monitor on the ReferenceQueue.
- T1 removes the Reference, setting Reference.queue = NULL.
- T1 gets preempted by the scheduler before it can release the monitor on the ReferenceQueue.
- some thread T2 starts to call Reference.enqueue(), acquires the monitor on the Reference
- T2 skips passes through the existing "if (r.queue == ENQUEUED) return false;" test
- T2 blocks on the monitor on the ReferenceQueue (it is held by T1).
- scheduler resumes T1, which releases the monitor on the ReferenceQueue.
- scheduler resumes T2, which takes the monitor on the ReferenceQueue and puts the same Reference back into the queue.
- T2 sees Reference.enqueue() return true for the same Reference that T1 saw it return true on.
- A future ReferenceQueue.poll() will dequeue the same Reference again.
If the application is using the ReferenceQueue to implement reference counting based resource management, a double dequeue of the same reference is unexpected. The Javadoc for Reference.enqueue() seems to imply that a single Reference instance will enqueue/dequeue exactly once from its registered ReferenceQueue, but as the scenario above outlines, that isn't true.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I expected to see each Reference instance enqueue/dequeue exactly once from the registered ReferenceQueue. Instead a Reference can enqueue/dequeue an infinite number of times.
REPRODUCIBILITY :
This bug can be reproduced always.
CUSTOMER SUBMITTED WORKAROUND :
Maintain a cleared flag in your Reference subclass, e.g.:
public class MyRef<V> extends SoftReference<V> {
private boolean cleared;
public MyRef(V v, ReferenceQueue<V> q) {
super(v, q);
}
public boolean canClear() {
if (cleared) return false;
cleared = true;
return true;
}
}
MyRef<V> r;
while ((r = (MyRef<V>) queue.poll()) != null) {
if (!r.canClear()) continue;
// normally handle the reference as this is the one (and only) dequeue
}
java version "1.6.0_01"
Java(TM) SE Runtime Environment (build 1.6.0_01-b06)
Java HotSpot(TM) Server VM (build 1.6.0_01-b06, mixed mode)
Problem also exists in JDK6 Mercurial repository http://hg.openjdk.java.net/jdk6/jdk6/jdk/summary as of changeset 135 a42d6999734b
ADDITIONAL OS VERSION INFORMATION :
Linux 2.6.24-gg23-generic #1 SMP Fri Jan 30 14:07:49 PST 2009 x86_64 GNU/Linux
A DESCRIPTION OF THE PROBLEM :
It is possible for a Reference.enqueue() call to return true twice on the same Reference instance.
The issue appears to be that ReferenceQueue.enqueue(Reference) does not check for
if (r.queue == NULL) return false;
Consequently what can happen is:
- some thread T1 enqueues the reference via Reference.enqueue().
- T1 calls ReferenceQueue.poll() and takes the monitor on the ReferenceQueue.
- T1 removes the Reference, setting Reference.queue = NULL.
- T1 gets preempted by the scheduler before it can release the monitor on the ReferenceQueue.
- some thread T2 starts to call Reference.enqueue(), acquires the monitor on the Reference
- T2 skips passes through the existing "if (r.queue == ENQUEUED) return false;" test
- T2 blocks on the monitor on the ReferenceQueue (it is held by T1).
- scheduler resumes T1, which releases the monitor on the ReferenceQueue.
- scheduler resumes T2, which takes the monitor on the ReferenceQueue and puts the same Reference back into the queue.
- T2 sees Reference.enqueue() return true for the same Reference that T1 saw it return true on.
- A future ReferenceQueue.poll() will dequeue the same Reference again.
If the application is using the ReferenceQueue to implement reference counting based resource management, a double dequeue of the same reference is unexpected. The Javadoc for Reference.enqueue() seems to imply that a single Reference instance will enqueue/dequeue exactly once from its registered ReferenceQueue, but as the scenario above outlines, that isn't true.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I expected to see each Reference instance enqueue/dequeue exactly once from the registered ReferenceQueue. Instead a Reference can enqueue/dequeue an infinite number of times.
REPRODUCIBILITY :
This bug can be reproduced always.
CUSTOMER SUBMITTED WORKAROUND :
Maintain a cleared flag in your Reference subclass, e.g.:
public class MyRef<V> extends SoftReference<V> {
private boolean cleared;
public MyRef(V v, ReferenceQueue<V> q) {
super(v, q);
}
public boolean canClear() {
if (cleared) return false;
cleared = true;
return true;
}
}
MyRef<V> r;
while ((r = (MyRef<V>) queue.poll()) != null) {
if (!r.canClear()) continue;
// normally handle the reference as this is the one (and only) dequeue
}
- duplicates
-
JDK-8020452 (ref) Reference queues may return more entries than expected
- Closed