Why is finalize wrong? was: Benefits of activeReferenceQueue (original) (raw)
David Holmes david.holmes at oracle.com
Tue Jul 29 10:49:25 UTC 2014
- Previous message: Why is finalize wrong? was: Benefits of activeReferenceQueue
- Next message: WAR == single classloader was: Benefits of activeReferenceQueue
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Hi Jaroslav,
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 contexts.
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 created it.
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 applets).
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.
Cheers, David
-jt
- Previous message: Why is finalize wrong? was: Benefits of activeReferenceQueue
- Next message: WAR == single classloader was: Benefits of activeReferenceQueue
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]