In this example, run() method will be performed at the moment when data object will be ready for deallocation by garbage collector.
Important note: the implementation of Runnable interface must not contain any direct or indirect references to data object. In other case, the data instance will never become unreachable and the run() method will never be called. In particular, largeResources object, processed by run() method and accessible there via "final" declaration, must not refer to data instance in any ways. In other words, unlike the standard finalize() method, the finalization code, scheduled by this class, cannot refer to the finalized data.
Every Finalizer instance contains a daemon thread, that is started on the first call of {@link #invokeOnDeallocation(Object,Runnable) invokeOnDeallocation(checkedForDeallocation,task)} method.This thread looks, in an infinite loop, for deallocation of all objects, passed to that method, and runs corresponding tasks when the objects ("checked for deallocation") become unreachable. This thread will run all time until closing the application, if you will not stop it by {@link #shutdownNow()} method.So, you should avoid creating extra instances of Finalizer: please use one or several global finalizers for a package or application.
As well as for the classic finalize() method, there is no guarantee that finalization tasks scheduled by this class will be really performed before finishing the application. Usually, exiting the application just stops all daemon threads inside all instances of this class, and the tasks, which were not completed yet, are canceled.
To increase probability of performing all finalization tasks, you may add a code alike the following at the point when application is finished (or closed by a user):
long t = System.currentTimeMillis(); while (myFinalizer. {@link #activeTasksCount()} > 0) { System.runFinalization(); System.gc(); Thread.sleep(50); if (System.currentTimeMillis() - t > TIMEOUT_IN_MILLISECONDS) break; }
This "while" loop here waits until all tasks, scheduled in myFinalizer, will be successfully finished. The loop should be restricted by some suitable, not too long timeout:
If your system use several finalizers, you should perform the same loop for each one, or replace the single call of activeTasksCount() with the sum of results of this method for all finalizers:
... while (myFinalizer1. {@link #activeTasksCount()} + myFinalizer2. {@link #activeTasksCount()} + ... + myFinalizerN. {@link #activeTasksCount()} > 0) {...
It's possible that your task object contains references to some other "large" objects, which also should be finalized before finishing your application and which implement finalization in another way (for example, some standard Java objects as MappedByteBuffer). When the "while" loop, listed above, finishes, such objects become unreachable, but not really finalized yet. To be on the safe side, we recommend to add the following loop after the "while" loop listed above:
for (int k = 0; k < 5; k++) { // finalizing some additional objects that could be // referred from finalization tasks performed above System.runFinalization(); System.gc(); }
This class is thread-safe: you may use the same instance of this class in several threads.
AlgART Laboratory 2007–2014
@author Daniel Alievsky @version 1.2 @since JDK 1.5
|
|
|
|