RFR (XS): 8014890 : Reference queues may return more entries than expected
Thomas Schatzl
thomas.schatzl at oracle.com
Wed Jun 19 14:09:51 UTC 2013
Hi,
On Wed, 2013-06-19 at 17:56 +0400, Aleksey Shipilev wrote:
> On 06/19/2013 04:05 PM, David Holmes wrote:
> > I think I'm going to need a lot more time to understand this issue
> > completely. The synchronization being used seems complex and
> > somewhat ill-defined, and also inadequate. I'm not convinced that
> > adding code inside a synchronized block really fixes a race condition
> > caused by unsynchronized access - but it may well narrow the window
> > significantly.
>
> +1. Having spent 30 minutes trying to figure out the synchronization
> protocol for R and RQ, I can say that is a haunted part of JDK.
>
:) I had the same problem when trying to figure out the code.
> That said, I think the patch fixes the concrete issue. We are
> piggybacking on the mutual exclusion on RQ.lock to protect ourselves
> from the concurrent mutation of r.queue. The only two places where we
> mutate it is RQ.enqueue() and RQ.poll(), both secured with RQ.lock.
> Given the r.queue is not volatile, we should also acquire the same lock
> while reading r.queue, otherwise races obliterate the reasoning about
> the correctness.
>
> With that notion in mind, I start to wonder if we just need to move the
> check in enqueue() down into the synchronized(lock), and extend it to
> capture NULL:
>
> --- a/src/share/classes/java/lang/ref/ReferenceQueue.java Mon Jun 17
> 16:28:22 2013 +0400
> +++ b/src/share/classes/java/lang/ref/ReferenceQueue.java Wed Jun 19
> 17:53:24 2013 +0400
> @@ -56,8 +56,9 @@
>
> boolean enqueue(Reference<? extends T> r) { /* Called only by
> Reference class */
> synchronized (r) {
> - if (r.queue == ENQUEUED) return false;
> synchronized (lock) {
> + if (r.queue == ENQUEUED || r.queue == NULL)
> + return false;
> r.queue = ENQUEUED;
> r.next = (head == null) ? r : head;
> head = r;
>
> Will it be equivalent to what Thomas is trying to accomplish?
Yes, this is equivalent. Instead of checking the separate ENQUEUED and
NULL values I simply used an "r.queue != this" check which would get
both cases. R.queue cannot have other values than ENQUEUED, NULL or the
queue's value set at initialization.
I wanted to minimize the changes for this particular CR.
Thanks,
Thomas
More information about the core-libs-dev
mailing list