Why is finalize wrong? was: Benefits of activeReferenceQueue
david.holmes at oracle.com
Tue Jul 29 10:49:25 UTC 2014
On 29/07/2014 7:24 PM, Jaroslav Tulach wrote:
> Hello David,
> the following suggestions are hard to argue with as they touch philosophical
> aspects of software engineering. In spite of that I will attempt to analyze
> and argue:
Always happy to get philosophical about software design :)
> Dne Út 29. července 2014 18:16:24, David Holmes napsal(a):
>> I think the fundamental flaw of activeReferenceQueue is in trying to
>> hide the thread management from the user.
> I guess this builds on top of bad experience with Object.finalize() method. No
> doubt existence of the method is failure, but why?
> # 1 - Because of automatic JDK management thread?
> # 2 - Or because once finalize() is called, one still has reference to the
> "gone" object and can re-activate it?
> #3 - Or because the finalizer thread is shared between completely unrelated
> objects and misbehavior of one can cause problems for others?
> My personal top three starts with #2. That is logically invalid. #3 can be a
> problem, but so can be any other misbehaving thread in an application. #1 is
> completely OK, from my perspective (if the thread can GC when necessary).
I think you are conflating different issues that happen to come together
in this case. finalization is problematic - no doubt about it - it was a
flawed idea (with good intentions) to get around lack of destructors to
support C++ style RAII (resource acquisition is initialization) idiom.
Weak references and reference queues were introduced to address some of
the short comings of finalization as well as providing other
capabilities within a GC'd environment.
The threading aspect is somewhat tangential. Any time you choose to
introduce a new thread to perform a task you have to be concerned about
the lifetime of the task and thus the thread. Telling a thread when it
should stop a repetitive task is one of the key design points of
multi-threaded solutions. Automatic threading solutions work fine for
one-shot tasks, from a lifecycle management perspective, but otherwise
you either have to expose management methods, or else assume an
environment when the thread's lifecycle is that of the "application".
And as per the case at hand the latter is a problem when we have these
environments that almost, but not quite, provide independent execution
> I'd like to point out that activeReferenceQueue does not have #2 problem at
> all. So in my eyes it behaves fine (once we allow its thread to GC properly).
The GC issue is somewhat incidental - the key issue is "when should this
thread stop doing what it does?".
>> By automating the threading
>> there is no way to control the lifecycle of the thread and hence we have
>> the problem at hand. When the application code manages the thread
>> itself, then it can also manage its lifecycle and avoid the problem.
> Alas, the primary (and only generally available) way to find out that something
> is not used in Java SE is wait when it gets garbage collected, right?
Equating lifecycle with "reachability" is convenient but it is inexact.
Though you could argue that the problem here is an extension of the
normal "cyclical garbage" problem - the GC can't know that the
processing thread in this case is itself "garbage" because nothing can
submit any more work for it to do.
Maybe that is a solvable problem, but to me, here and now,
responsibility for shutting down the thread lies with the subsystem that
> Application frameworks on top of Java have notion of a lifecycle, but it is
> different for Servlets, for NetBeans Platform, and any other framework. When
> writing general purpose library in Java, GC is the only tool in hand.
Alas just because all you own is a hammer it doesn't turn everything
into a problem solvable with nails.
The Java platform provides a number of "execution contexts" with
short-comings in lifecycle management in my opinion (harking back to
>> This might be a case where some kind of user-level "reference counting"
>> would be a better solution. But of course that would require changes to
>> all existing users of the class.
> We tried some reference counting, but it is not reliable. Of course, all
> problems in software engineering can be solved by yet another level of
> indirection - I can create my own wrapper for WeakReference, ReferenceQueue
> and etc. and then I have everything under my control. But why not slightly
> improve the existing library and make it more flexible?
To modify the existing library requires establishing that the new
functionality is sufficiently general and "carries its weight" -
otherwise everyone has an improvement that helps their particular use-case.
Once you've painted yourself into a corner, hanging a rope from the
ceiling might seem like an obvious solution, but it's better to not
paint yourself into the corner to begin with.
More information about the core-libs-dev