Benefits of activeReferenceQueue (original) (raw)
Jaroslav Tulach jaroslav.tulach at oracle.com
Tue Jul 29 09:06:56 UTC 2014
- Previous message: Benefits of activeReferenceQueue was: ReferenceQueue.remove to allow GC of the queue itself
- Next message: Benefits of activeReferenceQueue
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Dne Út 29. července 2014 18:16:24, David Holmes napsal(a):
Thanks for the detailed explanation. It is an interesting problem.
Good. I am glad it attracted your attention. I am also glad Peter came with his static method...
On 29/07/2014 6:03 PM, Peter Levart wrote: > On 07/29/2014 04:16 AM, David Holmes wrote: >> Hi Jaroslav, >> >> So ... activeReferenceQueue is a reference queue that embodies a >> thread that does the polling and implements a psuedo-finalization >> mechanism. This works fine in the normal case where the lifetime of >> the queue is the lifetime of the "application". In the WAR case (and I >> don't know the details of WAR deployment) each time it is deployed in >> the same VM we get a new activeReferenceQueue and a new thread. >> >> The basic issue is that the thread has a strong reference to the queue >> and has no idea when it should exit and so the thread and queue remain >> forever even if there is no user code with a reference to the queue - >> does that sum it up? >> >> Can the thread not hold a weakreference to the queue and poll using >> remove(timeout) and then terminate when the queue reference is gone? >> >> Thanks, >> David > > The main problem I think is, that when calling queue.remove(timeout) the > thread does hold a strong reference to the queue for the entire time > it waits for something to be enqueued. So majority of time in a loop, > thread holds a strong reference to queue preventing it from being > considered for WeakReference processing or at least prolonging it's life > into an indefinite future (the window of opportunity for queue to be > found weakly reachable is very small). > > That's why Jaroslav is hacking with reflection to get hold of the 'lock' > so that he can re-implement the ReferenceQueue.remove(timeout) method > without holding a strong reference to the queue. If we wanted to make > Jaroslav's life easier, a method like the following in ReferenceQueue > could help him: > > > public class ReferenceQueue { > > ... > > public static class CollectedException extends Exception {} > > public static Reference<? extends T> remove( > > Reference<? extends ReferenceQueue> queueRef, > long timeout > > ) throws IllegalArgumentException, InterruptedException, > > CollectedException { > > if (timeout < 0) {_ _> > throw new IllegalArgumentException("Negative timeout value"); > > } > // obtain lock > Object lock = apply(queueRef, queue -> queue.lock); > > synchronized (lock) { > > Reference<? extends T> r = apply(queueRef, > > ReferenceQueue::reallyPoll); > > if (r != null) return r; > long start = (timeout == 0) ? 0 : System.nanoTime(); > for (; ; ) { > > lock.wait(timeout); > r = apply(queueRef, ReferenceQueue::reallyPoll); > if (r != null) return r; > if (timeout != 0) { > > long end = System.nanoTime(); > timeout -= (end - start) / 1000000; > if (timeout <= 0) return null;_ _> start = end; > > } > > } > > } > > } > > private static <R, T> R apply( > > Reference<? extends ReferenceQueue> queueRef, > Function<ReferenceQueue, R> func > > ) throws CollectedException { > > ReferenceQueue queue = queueRef.get(); > if (queue == null) throw new CollectedException(); > return func.apply(queue); > > } > > ... > > This is basically a re-implementation of ReferenceQueue.remove(int > timeout) instance method in terms of a static method, which only briefly > "touches" the queue instance wrapped in a Reference but majority of time > it waits for notification while only holding a Reference to the queue.
... because as we look at the patch attached to issue: https://bugs.openjdk.java.net/browse/JDK-8051843 we can find out it uses very similar approach: https://bugs.openjdk.java.net/secure/attachment/21429/X.diff
But that's only half of the story. The other half is how a thread finds > out that the queue has been collected so it can exit.
Well, the patch https://bugs.openjdk.java.net/secure/attachment/21429/X.diff solves that by its
- private static class Locks extends ReferenceQueue {
@Override
boolean enqueue(Reference<? extends Object> r) {
if (r instanceof Lock) {
synchronized (r) {
r.notifyAll();
}
}
return false;
}
- }
part. As the test at the end of the patch shows, the solution behaves find. -jt
- Previous message: Benefits of activeReferenceQueue was: ReferenceQueue.remove to allow GC of the queue itself
- Next message: Benefits of activeReferenceQueue
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]