@GwtIncompatible public class FinalizableReferenceQueue extends java.lang.Object implements java.io.Closeable
FinalizableReference.finalizeReferent()
on them.
Keep a strong reference to this object until all of the associated referents have been
finalized. If this object is garbage collected earlier, the backing thread will not invoke finalizeReferent()
on the remaining references.
As an example of how this is used, imagine you have a class MyServer
that creates a a
ServerSocket
, and you would like to ensure that the ServerSocket
is closed even if the MyServer
object is garbage-collected without calling
its close
method. You could use a finalizer to accomplish this, but that has a
number of well-known problems. Here is how you might use this class instead:
public class MyServer implements Closeable {
private static final FinalizableReferenceQueue frq = new FinalizableReferenceQueue();
// You might also share this between several objects.
private static final Set<Reference<?>> references = Sets.newConcurrentHashSet();
// This ensures that the FinalizablePhantomReference itself is not garbage-collected.
private final ServerSocket serverSocket;
private MyServer(...) {
...
this.serverSocket = new ServerSocket(...);
...
}
public static MyServer create(...) {
MyServer myServer = new MyServer(...);
final ServerSocket serverSocket = myServer.serverSocket;
Reference<?> reference = new FinalizablePhantomReference<MyServer>(myServer, frq) {
public void finalizeReferent() {
references.remove(this):
if (!serverSocket.isClosed()) {
...log a message about how nobody called close()...
try {
serverSocket.close();
} catch (IOException e) {
...
}
}
}
};
references.add(reference);
return myServer;
}
public void close() {
serverSocket.close();
}
}
Modifier and Type | Class and Description |
---|---|
(package private) static class |
FinalizableReferenceQueue.DecoupledLoader
Try to load Finalizer in its own class loader.
|
(package private) static class |
FinalizableReferenceQueue.DirectLoader
Loads Finalizer directly using the current class loader.
|
(package private) static interface |
FinalizableReferenceQueue.FinalizerLoader
Loads Finalizer.class.
|
(package private) static class |
FinalizableReferenceQueue.SystemLoader
Tries to load Finalizer from the system class loader.
|
Modifier and Type | Field and Description |
---|---|
private static java.lang.String |
FINALIZER_CLASS_NAME |
(package private) java.lang.ref.PhantomReference<java.lang.Object> |
frqRef |
private static java.util.logging.Logger |
logger |
(package private) java.lang.ref.ReferenceQueue<java.lang.Object> |
queue
The actual reference queue that our background thread will poll.
|
private static java.lang.reflect.Method |
startFinalizer
Reference to Finalizer.startFinalizer().
|
(package private) boolean |
threadStarted
Whether or not the background thread started successfully.
|
Constructor and Description |
---|
FinalizableReferenceQueue()
Constructs a new queue.
|
Modifier and Type | Method and Description |
---|---|
(package private) void |
cleanUp()
Repeatedly dequeues references from the queue and invokes
FinalizableReference.finalizeReferent() on them until the queue is empty. |
void |
close() |
(package private) static java.lang.reflect.Method |
getStartFinalizer(java.lang.Class<?> finalizer)
Looks up Finalizer.startFinalizer().
|
private static java.lang.Class<?> |
loadFinalizer(FinalizableReferenceQueue.FinalizerLoader... loaders)
Iterates through the given loaders until it finds one that can load Finalizer.
|
private static final java.util.logging.Logger logger
private static final java.lang.String FINALIZER_CLASS_NAME
private static final java.lang.reflect.Method startFinalizer
final java.lang.ref.ReferenceQueue<java.lang.Object> queue
final java.lang.ref.PhantomReference<java.lang.Object> frqRef
final boolean threadStarted
public FinalizableReferenceQueue()
public void close()
close
in interface java.io.Closeable
close
in interface java.lang.AutoCloseable
void cleanUp()
FinalizableReference.finalizeReferent()
on them until the queue is empty. This method is a
no-op if the background thread was created successfully.private static java.lang.Class<?> loadFinalizer(FinalizableReferenceQueue.FinalizerLoader... loaders)
static java.lang.reflect.Method getStartFinalizer(java.lang.Class<?> finalizer)