Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / GUI / November 2004

Tip: Looking for answers? Try searching our database.

Thread-question

Thread view: 
Ao - 05 Nov 2004 16:02 GMT
Hi everybody,

when closing my program I would like to start a Thread which does some
cleaning up in the background, but opf course before exiting I need to
be sure, that this Thread has finished running...

How can I wait for that Thread to finish, the following code does work,
but freezes my UI...

...
private boolean cleanedUp = false;

...
public void programmBeenden() {
  Thread cleaner = new Thread() {
    public void run() {
      // clean up some things...
      cleanedUp=true;
    }
  }
  cleaner.start();

  // ... do some other stuff
  // finally wait for cleaner to finish
  while(!cleanedUp) {
    try {
      Thread.sleep(100);
    } catch(InterruptedExecption iuE) {}
  }

  System.exit(0);
}

What else can I do to make sure that cleaner has finished without
freezing my UI.

Thanks, Aloys
Thomas Weidenfeller - 05 Nov 2004 16:31 GMT
Please post to one group only. Your question is not that important.

> How can I wait for that Thread to finish, the following code does work,
> but freezes my UI...

There is some information about this in the comp.lang.java.gui FAQ. You
are blocking the EDT.

Maybe you also want to read about shutdown hooks, SwingWorker and the
Swing threading model in general.

Regarding the problem of waiting for a thread: Thread.join();

/Thomas
shakahshakah@gmail.com - 05 Nov 2004 16:32 GMT
FWIW, and depending on the what you are trying to accomplish, you may
not have to explicitly wait for the worker thread to finish. In the
absence of an explicit  call to  System.exit(), your application won't
exit until all (non-daemon) threads have exited.
xarax - 05 Nov 2004 20:55 GMT
> FWIW, and depending on the what you are trying to accomplish, you may
> not have to explicitly wait for the worker thread to finish. In the
> absence of an explicit  call to  System.exit(), your application won't
> exit until all (non-daemon) threads have exited.

The AWT EDT is non-daemon, thus the call to System.exit()
is required to shutdown the JVM.

Just put the System.exit(0) call in the other
thread that performs the clean-up. Don't bother
with Thread.join() in the EDT; it will just hang
the GUI.
hiwa - 06 Nov 2004 01:15 GMT
> but freezes my UI...

See Q3.1, 3.2 and 4 .2 of the FAQ:
http://groups.google.com/groups?hl=en&lr=&selm=cjr8er%24oo0%241%40newstree.wise.
edt.ericsson.se


Also, Runtime#addShutdownHook() may be of your service.
Babu Kalakrishnan - 06 Nov 2004 08:00 GMT
> when closing my program I would like to start a Thread which does some
> cleaning up in the background, but opf course before exiting I need to
> be sure, that this Thread has finished running...

Runtime.getRuntime().addShutdownHook()

BK
Yakov - 06 Nov 2004 13:33 GMT
> Hi everybody,
>
> when closing my program I would like to start a Thread which does some
> cleaning up in the background, but opf course before exiting I need to
> be sure, that this Thread has finished running...

If you want to exit your app only after some code is finished, do not
even bother with threads. Just create another method with required
code, and the last line of your program should be a call of this
method.
Thomas G. Marshall - 09 Nov 2004 15:17 GMT
Yakov coughed up:
>> Hi everybody,
>>
[quoted text clipped - 6 lines]
> code, and the last line of your program should be a call of this
> method.

That is not going to work in general.

His "code" that you refer to could easily just be firing up a pile of GUI
and then do nothing more.  Setting up the GUI is (usually) by nature
non-blocking, this leaves no particular good time for that last line of his
program to run.

The other suggestions in this thread are better.

Signature

http://www.allexperts.com is a nifty way to get an answer to just about
/anything/.

Andy Flowers - 09 Nov 2004 18:44 GMT
Have you thought about overriding finalize() in the objects you wish to have
some final clean up ?

> Hi everybody,
>
[quoted text clipped - 33 lines]
>
> Thanks, Aloys
Carl Howells - 09 Nov 2004 18:48 GMT
> Have you thought about overriding finalize() in the objects you wish to have
> some final clean up ?

Bad idea. On most modern JVMs, finalizers seriously mess up garbage
collection.  In fact, if the JVM can avoid it, it'll just *not* collect
objects with finalizers.  It's not a very good way to get code run.

If you need post-collection cleanup of non-memory resources, remember
that PhantomReference is your friend.
Chris Uppal - 10 Nov 2004 09:16 GMT
> Bad idea. On most modern JVMs, finalizers seriously mess up garbage
> collection.

I have to say that I find this implausible.  Obviously finalisation adds
overhead to the GC operation, but that's because it's doing extra work --
/useful/ extra work -- but it sounds as if you mean something more than that.
Do you have any references ?

> In fact, if the JVM can avoid it, it'll just *not* collect
> objects with finalizers.  It's not a very good way to get code run.

It's perfectly at liberty not to collect anything.  But again you seem to be
going beyond that and stating that it (they) will discriminate against objects
with finalisers.  Again, this sounds implausible.  Do you have a reference for
it ?

(BTW I don't think finalisation is likely to be at all appropriate as a
solution to the OP's problem.)

   -- chris
John C. Bollinger - 10 Nov 2004 14:40 GMT
>>Bad idea. On most modern JVMs, finalizers seriously mess up garbage
>>collection.
[quoted text clipped - 3 lines]
> /useful/ extra work -- but it sounds as if you mean something more than that.
> Do you have any references ?

I haven't looked up references (yet) but my understanding is that Carl
is correct, if perhaps overly emphatic.  Based only on the API docs and
JLS, one can argue that instances of classes that do not override
finalize() can be collected without actually invoking Object.finalize(),
as the VM can know that its Object.finalize() is specified to do
nothing.  More importantly, however, it is possible for a finalize()
method to make the object it is invoked on reachable again (an odd state
indeed: finalized and reachable), so after finalizing an object with a
non-default finalizer, the GC must completely redo its reachability
analysis for that object.  Naturally, that also affects the reachability
of objects to which the one in question holds references.

The VM must also keep track of whether or not reachable objects have
been finalized, because they are only ever finalized once (per
specification).  That probably doesn't add much overhead, but it may
result in unexpected behavior when the second time an object becomes
unreachable it is discarded without its finalizer being invoked.

>>In fact, if the JVM can avoid it, it'll just *not* collect
>>objects with finalizers.  It's not a very good way to get code run.
[quoted text clipped - 3 lines]
> with finalisers.  Again, this sounds implausible.  Do you have a reference for
> it ?

That would be an implementation question, but I suspect that many Java
GC implementations indeed do exactly as Carl describes.  It really is a
much bigger deal to collect an object with a non-default finalizer than
to collect other objects.

It might be a little too strong to say that Java's finalization
mechanism is broken, but I have never personally run into any task to
which it is suited.  It is definitely a trap, because people --
especially those with experience in some other OO languages, such as C++
-- tend to make incorrect assumptions about how finalization works.  It
has been said here before and it will be repeated again: a Java
finalizer is not at all the same thing as a C++ destructor.

John Bollinger
jobollin@indiana.edu
Thomas G. Marshall - 10 Nov 2004 15:32 GMT
John C. Bollinger coughed up:

>>> Bad idea. On most modern JVMs, finalizers seriously mess up garbage
>>> collection.
[quoted text clipped - 22 lines]
> result in unexpected behavior when the second time an object becomes
> unreachable it is discarded without its finalizer being invoked.

There are a few places within the java documentation, api and JLS, where
/required/ behavior is not /quite/ pinned down to my liking.  Precisely
/what/ the GC is required to do on various platforms is one of them.  I
consider it one of my bigger gripes.

...[rip]...

Signature

"Gentlemen, you can't fight in here! This is the War Room!"

John C. Bollinger - 10 Nov 2004 16:08 GMT
> John C. Bollinger coughed up:
>>I haven't looked up references (yet) but my understanding is that Carl
[quoted text clipped - 20 lines]
> /what/ the GC is required to do on various platforms is one of them.  I
> consider it one of my bigger gripes.

There is a tension in most language and API specifications between
pinning down requirements very precisely so as to provide the least
ambiguous definitions, and describing requirements more generally so as
to allow more flexibility in implementation.  Too far in either
direction doesn't make sense.  Moreover, implementations typically
operate under an "as if" principle (any behavior is acceptable as long
as to any external observer it is indistinguishable from the specified
behavior).

In the case of GC, the API docs for Object.finalize() give a fairly
extensive discussion of the question, and JLS(2e) 12.6 covers the topic
in (IMO) reasonably complete detail, including an object lifecycle
diagram in 12.6.1.  I believe everything I discussed (above) is in fact
described by the specification, even including the VM skipping
invocation of finalize() when it has not been overridden.  I am
satisfied with the precision of the specification in that area; what
details would you prefer to see more completely specified?

John Bollinger
jobollin@indiana.edu
Thomas G. Marshall - 10 Nov 2004 19:28 GMT
John C. Bollinger coughed up:

>> John C. Bollinger coughed up:
>>> I haven't looked up references (yet) but my understanding is that
[quoted text clipped - 38 lines]
> I am satisfied with the precision of the specification in that area;
> what details would you prefer to see more completely specified?

Not from finalize in particular, but from the gc in general.

Take for example System.gc() api doc:

       Calling the gc method suggests that the Java
       Virtual Machine expend effort toward recycling
       unused objects in order to make the memory
       they currently occupy available for quick reuse.
       When control returns from the method call, the
       Java Virtual Machine has made a best effort to
       reclaim space from all discarded objects.

That last statement is misleading.  It does not have to make a "best effort"
at that point at all.  It's "best effort" can easily be to ignore the call
entirely without attempt.

Signature

Whyowhydidn'tsunmakejavarequireanuppercaselettertostartclassnames....

John C. Bollinger - 12 Nov 2004 17:41 GMT
> John C. Bollinger coughed up:
>>I am satisfied with the precision of the specification in that area;
[quoted text clipped - 15 lines]
> at that point at all.  It's "best effort" can easily be to ignore the call
> entirely without attempt.

Well, what would you prefer that it say?  Would it satisfy you if
something were added to that documentation to the effect of "The
definition of 'best effort' depends on the memory management
implementation in use in the Virtual Machine at the time of this
method's invocation.  It is possible that the implementation's 'best
effort' is in fact no effort at all."?  That wouldn't be any more
specific, but it would at least be explicit about its lack of specificity.

Would you be willing to restrict the possible GC implementations by
specifying their required operation in more detail?  More importantly,
how does the lack of detail in these areas interfere with your ability
to develop Java programs?

John Bollinger
jobollin@indiana.edu
Chris Uppal - 12 Nov 2004 09:50 GMT
> > > Bad idea. On most modern JVMs, finalizers seriously mess up garbage
> > > collection.
[quoted text clipped - 7 lines]
> is correct, if perhaps overly emphatic.  Based only on the API docs and
> JLS, [...discussion snipped...]

I agree that it will make the GC system do more work, but I don't see that it's
"messing up" the GC, just that finalisation interacts with GC.

The "obvious" way to implement it (actually, I can't think of a better way, but
I suspect there almost certainly /are/ better ways) would go something like
this:

When an object with a non-empty finalize() method is created, a flag is set in
its header -- meaning "must finalise".  When GC discovers an object to be
"unreachable" it checks the flag, if that flag is not set then it <does
whatever it would normally>, otherwise it adds it to a queue serviced by a
finaliser thread (so the object has now become reachable again), and moves on.
The finaliser thread sits waiting on the queue; when something appears, it
takes it off the queue, clears the "must finalise" flag, and executes the
object's finalize() method (trapping and ignoring all exceptions).  It then
moves on to the rest of the queue.  If the object has not become reachable
again then when the GC next re-visits it, it will be reclaimed.

Now if a real implementation is anything like the above, then I don't think its
helpful to describe finalisation as "messing up" the GC.  The system as a whole
has to do a little more work for each finalisable object -- but that's fair, we
/want/ it to do more work otherwise the finaliser wouldn't get run.  But the GC
itself is just doing its normal job and is not impeded by the presence of
finalisable objects.  (Of course it could run faster if the spec didn't allow
finalisation at all, in which case there would be no need to check any flags).

Notice how the finalisable object's finalise method can get called almost
arbitrarily later than when it was first discovered to be unreachable.  Notice
also that its eventual reaping is also postponed, happening at least one GC
cycle later than when it was first "noticed" by the GC, even if the finaliser
thread is keeping up with the rate that objects are put on its queue.  But
those delays are not symptomatic of the system being prevented from working
properly, they are just the expected result of the design.

> > It's perfectly at liberty not to collect anything.  But again you seem
> > to be going beyond that and stating that it (they) will discriminate
[quoted text clipped - 5 lines]
> much bigger deal to collect an object with a non-default finalizer than
> to collect other objects.

I don't think that's the right way to look at it.  It is no bigger deal to GC a
finalisable object than any other (except, of course, that it has to be GCed
twice).  The lifetime of a finalisable object is more complicated than other
objects -- naturally -- and the system does more work as the object dies than
it would otherwise need to, but that's just natural.   It's sort of like saying
"don't make objects serialisable since the system will have to do more work
when it serialises them" ;-)  That's not to say that finalisation's /free/, or
even that it's /cheap/ -- it has costs, just like anything else.

For comparison: it /would/ be fair to describe it as "messing up" GC if the
actual use of finalisation made other objects harder to re-claim.  For instance
if the implementation of reference queues were such that every reclaimed object
had to be checked against all the existing queues (impossible to believe the
implementation /is/ like that!), then each new queue would add extra load to
the /whole/ system.  In such a case it would be very correct to say that
reference queues mess up GC.

> It might be a little too strong to say that Java's finalization
> mechanism is broken,

Unless, of course, it actually /is/ broken -- that's an implementation
question.  I haven't heard of any problems with the Sun implementation myself,
but there could easily (-ish) /be/ such problems that Carl has heard of but I
had not.  Which is why I asked.

> but I have never personally run into any task to
> which it is suited.  It is definitely a trap, because people --
> especially those with experience in some other OO languages, such as C++
> -- tend to make incorrect assumptions about how finalization works.  It
> has been said here before and it will be repeated again: a Java
> finalizer is not at all the same thing as a C++ destructor.

It can certainly mislead C++ programmers -- we see it here often (I'm sure
you're as sick of it as me).  It can also be abused, especially if people think
they can use it to clean up and reclaim system resources that are significantly
more scarce than normal object memory.  (The incredibly stupid example of NIO
system buffers leaps to mind).  But I think it has its uses.  As I've said
before, finalisation is (IMO) best viewed as a kind of reflection -- reflecting
on an object's lifetime -- and like all reflection it's not something you are
going to need every day.  Depending on what kind of programming you do, you can
go a lifetime and never use it.  But if you do need it, then /boy/ do you need
it...

   -- chris
Carl Howells - 10 Nov 2004 18:54 GMT
>>Bad idea. On most modern JVMs, finalizers seriously mess up garbage
>>collection.
[quoted text clipped - 11 lines]
> with finalisers.  Again, this sounds implausible.  Do you have a reference for
> it ?

Observed behavior.  I just wrote up this test:

----------- Test2.java -----------
import java.util.*;
import java.lang.ref.*;

public class Test2
{
    public static void main(String [] args)
    {
        System.out.println(System.getProperty("java.version"));
        System.out.println(System.getProperty("java.vendor"));
        System.out.println();

        int [] sizes = {10, 100, 1000, 10000, 100000, 1000000};

        for (int i = 0; i < sizes.length; i++)
        {
            test(sizes[i]);
        }
    }

    private static void test(int size)
    {
        ReferenceQueue q = new ReferenceQueue();
        Set s = new HashSet();

        int count = 0;
        int nfcount = 0;
        int wfcount = 0;

        while (count < size)
        {
            s.add(new BooleanReference(new Object(), q, false));
            s.add(new BooleanReference(new WithFinalizer(), q, true));

            BooleanReference br;
            while ((br = (BooleanReference)q.poll()) != null)
            {
                s.remove(br);
                count++;
                if (br.flag)
                {
                    wfcount++;
                }
                else
                {
                    nfcount++;
                }
            }
        }

        System.out.println(count + " object collected.");
        System.out.println("Objects with finalizer collected: " + wfcount);
        System.out.println("Objects without finalizer collected: " +
nfcount);
        System.out.println();
    }

    private static class WithFinalizer
    {
        private static int whatever;

        protected void finalize()
        {
            whatever++;
        }
    }

    private static class BooleanReference extends PhantomReference
    {
        public boolean flag;

        public BooleanReference(Object referent, ReferenceQueue q,
boolean flag)
        {
            super(referent, q);
            this.flag = flag;
        }
    }
}
----------- end Test2.java -----------

I had a bit of an issue with an earlier version, as when I wasn't saving
BooleanReferences they were getting collected before the objects they
were referring to, which kind of made things more difficult.  :)

Anyway, here's the output of two different runs through it:

1.4.2_03
Sun Microsystems Inc.

242 object collected.
Objects with finalizer collected: 0
Objects without finalizer collected: 242

5723 object collected.
Objects with finalizer collected: 0
Objects without finalizer collected: 5723

5673 object collected.
Objects with finalizer collected: 0
Objects without finalizer collected: 5673

12115 object collected.
Objects with finalizer collected: 1957
Objects without finalizer collected: 10158

113516 object collected.
Objects with finalizer collected: 45157
Objects without finalizer collected: 68359

1093806 object collected.
Objects with finalizer collected: 487562
Objects without finalizer collected: 606244

-----------

1.5.0
Sun Microsystems Inc.

211 object collected.
Objects with finalizer collected: 0
Objects without finalizer collected: 211

1288 object collected.
Objects with finalizer collected: 0
Objects without finalizer collected: 1288

5707 object collected.
Objects with finalizer collected: 0
Objects without finalizer collected: 5707

20398 object collected.
Objects with finalizer collected: 5711
Objects without finalizer collected: 14687

111297 object collected.
Objects with finalizer collected: 46748
Objects without finalizer collected: 64549

1026543 object collected.
Objects with finalizer collected: 476431
Objects without finalizer collected: 550112

-----------

So, there's definately a bias against objects with finalizers in those
JVMs.  The bias becomes less extreme as more and more objects are
collected, but it's still present.
Chris Uppal - 12 Nov 2004 10:18 GMT
> Observed behavior.  I just wrote up this test:

An interesting example, thanks.

> So, there's definately a bias against objects with finalizers in those
> JVMs.  The bias becomes less extreme as more and more objects are
> collected, but it's still present.

I think that you are seeing the effect of objects having to wait on the
finaliser thread's queue (see my reply to John Bollinger).  Unless your test
was running on a multi-processor machine (and possibly even if it was) then the
finaliser will have been contending for CPU time with your executing loops, and
so it won't have been able to run as often as it would "like to".  If that
surmise is correct, then adding a small delay to your loop should give it a
chance to run and clean up.

Notice, by the way, that your use of reference queues is essentially the same
as how the system (I think) implements finalisation.  The GC sees that an
object is "special" and instead of just wiping it, it places it on a queue for
some other thread (or other processing) to deal with.  In the case of your
example, it is placing the reference object onto the queue rather than the dead
object itself, but the logic is similar to finalisation (though I'd guess that
it's marginally more expensive to execute).  The bit that corresponds to the
finaliser thread's activity is your loop where you poll() the queue.

From the look of the results you quoted, your own loop has a slight advantage
over the finaliser thread's loop, but I don't know whether that is simply
reflecting an "unfair" advantage due to being scheduled more often, or is
because of some other aspect of the implementation.  At the minimum, there's an
"unfair" advantage to your loop in that the results are reported when /it/ has
finished, but without also waiting for the finaliser to finish.  In a sense,
your loop gets to decide when the "race" is over, so even if it and the
finaliser were working at the same speed on average, we'd never see the
finaliser "beat" your loop, we could only ever see it "draw" or "loose".

   -- chris
Thomas G. Marshall - 12 Nov 2004 15:31 GMT
Chris Uppal coughed up:

>> Observed behavior.  I just wrote up this test:
>
[quoted text clipped - 18 lines]
> places it on a queue for some other thread (or other processing) to
> deal with.

Yeah, I'm guessing that's right.  The end result is that there is a
reference /somewhere/ in all the gobledy gook (in a queue with all the other
finalizer objects) that keeps the object from being marked for the M&S gc
algorithm.

> In the case of your example, it is placing the reference
> object onto the queue rather than the dead object itself, but the
> logic is similar to finalisation (though I'd guess that it's
> marginally more expensive to execute).  The bit that corresponds to
> the finaliser thread's activity is your loop where you poll() the
> queue.

I think your conclusion so far has been fairly on the money here.  It isn't
ruining the gc algorithm per se, it is merely making it even /harder/ to
predict.

> From the look of the results you quoted, your own loop has a slight
> advantage over the finaliser thread's loop, but I don't know whether
[quoted text clipped - 9 lines]
>
>     -- chris

Signature

http://www.allexperts.com is a nifty way to get an answer to just about
/anything/.

Gordon Beaton - 12 Nov 2004 10:49 GMT
>> Bad idea. On most modern JVMs, finalizers seriously mess up garbage
>> collection.
[quoted text clipped - 3 lines]
> extra work -- /useful/ extra work -- but it sounds as if you mean
> something more than that.

The extra work done by finalization may be useful, but there is no
added value if you could have done it yourself with a suitable
dispose() method. However the cost is there regardless.

> Do you have any references ?

Here's one:
 http://servlet.java.sun.com/javaone/javaone2000/event.jsp?eventId=1172

(In particular, pages (approx) 30-36 of the slides)

Although this was presented 4 years ago and some implementation
details have likely changed since then, several of the arguments he
presents against finalization (e.g. average age of objects and the
resulting effect on process size) certainly hold regardless of
implementation.

In particular, one aspect he mentions that seems to be missing from
this discussion, is the tree of objects that are artificially kept
alive because of references from (other) objects waiting for
finalization. Longer average object life leads to more live objects at
any given time, and consequently more work for the garbage collector.

If I've understood correctly, objects that use finalization must be
queued for gc a second time, after finalization has run.

Similar comments can be found in appendix A "The truth about garbage
collection, in "Java platform performace":
 http://java.sun.com/developer/Books/performance/

Here's another:
 http://www-106.ibm.com/developerworks/java/library/j-jtctips/j-jtc0319a.html

/gordon

Signature

[  do not email me copies of your followups  ]
g o r d o n + n e w s @  b a l d e r 1 3 . s e

Chris Uppal - 16 Nov 2004 11:49 GMT
[re-ordered]

> [...] seems to be missing from
> this discussion, is the tree of objects that are artificially kept
> alive because of references from (other) objects waiting for
> finalization. Longer average object life leads to more live objects at
> any given time, and consequently more work for the garbage collector.

This is undoubtedly true.  Still, I'm finding it hard to imagine convincing
examples of the proper use of finalisation where this would be an issue (but
see below).

BTW, don't forget that /not/ relying on finalisation can have costs too.  More,
and more complicated, code.  More opportunity for error.  Even, potentially
larger object networks -- e.g. if an object that may need cleanup cannot just
be handed-over to another context and forgotten, then the recieving context may
have to keep a link back to the supplier so that it can "hand back" the object
when it has finished with it.

One thing that this discussion has brought into focus for me, which I hadn't
noticed before, is that not allowing the programmer to manipulate the "must
finalise" flag (posited in an early post) is a fairly big design error in Java.
For one thing, as everyone knows, finalisation only ever happens once -- which
is a very strange situation for an object that is allowed to "resurect" itself
in its finaliser.  But the more serious problem is that there is no way for us
to tell the JVM that finalisation will /not/ be needed for a given object.  For
instance when we clean up explicitly in a cleanUp() method, then we should be
able to say something like:
   this.beNotFinalizable()
to clear the (hypothetical) "must finalise" flag and allow the object to die
normally without the various overheads (including keeping object networks
alive) of finalization.

Actually, I'd prefer to have beFinalizable() and beNotFinalizable() as
(probably protected) methods of Object, and for "finalisability" to be off for
all objects, by default, regardless of whether they defined a finalize()
method.  I.e. it should be the programmer's responsibility to manipulate
finalisability as necessary, not left up to an ill-defined system
"optimisation".

> > Do you have any references ?
>
> Here's one:
>   http://servlet.java.sun.com/javaone/javaone2000/event.jsp?eventId=1172
>
> (In particular, pages (approx) 30-36 of the slides)

I get the impression from those slides that he's attempting to "demonise"
finalisation.  It's difficult to tell from presentation slides, but if I saw
the same claimes in a carefully worded article, then I'd accuse him of muddled
thinking and slanted examples. (<aside> why-oh-why do people /insist/ on
putting presentation slides on the Web ?  They are never any use --
presentation slides /shouldn't/ have enough words to be any use out-of-context.
It seems lazy to me </aside>).  I imagine that the backgound was that he was
seeing abuse and over-reliance on finalisation, and was attempting to
discourage its use.

   -- chris
John C. Bollinger - 16 Nov 2004 16:54 GMT
> One thing that this discussion has brought into focus for me, which I hadn't
> noticed before, is that not allowing the programmer to manipulate the "must
[quoted text clipped - 16 lines]
> finalisability as necessary, not left up to an ill-defined system
> "optimisation".

I think I have to disagree with you on this one, Chris.  The programmer
can already control this dimension to a limited extent by deciding
whether or not to override Object.finalize().  To be sure, that's a
per-class decision, not a per-object one, but I think that's where the
decision belongs.  It is also a design-time decision, not a runtime one,
but I'm okay with that.  I would rather put the onus on the designer to
adequately consider this issue than leave the developer to hack it out
as he sees fit (even if the same person operates in both roles).  I am
particularly not keen on the increased uncertainty about whether a
finalizer might run, and about how many times it might run.

Do you have a concrete-ish example of how your version of finalization
management would be an improvement over what Java already offers?  I
appreciate the general desire to have more control, but I don't really
see what it would gain you in this case.

John Bollinger
jobollin@indiana.edu
Chris Uppal - 20 Nov 2004 14:39 GMT
> > Actually, I'd prefer to have beFinalizable() and beNotFinalizable() as
> > (probably protected) methods of Object, and for "finalisability" to be
[quoted text clipped - 8 lines]
> per-class decision, not a per-object one, but I think that's where the
> decision belongs.

It's probably "agree to differ" time then ;-)   At a guess you a reasoning at
least partly by analogy with ordinary GC, where /not/ leaving memory
allocation/deallocation under the control of the programmer has too many
advantages to list ?

My position is that finalization itself is a fairly "heavy-weight" operation,
and as such is less well-suited to automation.  Mainly because there's more to
loose when (or if) the system doesn't handle it as well as I/we could if we
were doing it by hand.  (There's a definite parallel there with closing file
handles, which are too heavyweight to be suitable for handling completely
automatically -- by finalisation, for instance ;-)

The other reason I favour the more explicit approach is that I work with it
often and find it "feels" better (as I've mentioned before, I do more work in
Smalltalk than Java, and that's how the implementation I use works).  There is
an efficiency gain, of course, to being able to turn finalisation on only as
and when needed (during any specific object's total lifetime), and I don't
think that should be ignored.  But the other side of the coin is that I find
that code with explicit control of finalisation is actually /clearer/ than the
equivalent would be in Java.   That's because the normal pattern (virtually
universal) is that you do a (using Java syntax)
   this.beFinalizable();
at the time when you acquire a resource that must be released (such as an open
OS file handle  -- this is internal to the object that wraps that handle, of
course); and you do a
   this.beNotFinalizable();
at the time when you relinquish that resource.  I find that those methods act
as flags that show very clearly how the object does its resource management.
You might say that they form the skeleton of the design, and once you can see
that clearly, then it's easier to see where the flesh fits around it.

I find it particularly helpful in cases where the object is normally cleaned up
explicitly, but may also be handled by finalisation as a fall-back for when
explicit clean-up would overcomplicate the design.  In such cases it can be
difficult to get a handle on where the responsibility lies  -- which methods
you /may/ call, which ones you /must/ call, which ones you must /not/ call more
than once...   In such cases I start by looking for
beFinalizable()/beNotFinalizable() and the whole thing then normally becomes
crystal clear.

> Do you have a concrete-ish example of how your version of finalization
> management would be an improvement over what Java already offers?

Two somewhat indirect examples, and coming from slightly different directions.
I don't know how convicing you'll find them, but at least they are both real
examples, taken from the Smalltalk system I work with:

Database connections, and other similarly heavy-weight database-related objects
(prepared statements, etc) are best cleaned up explicitly (IMO).  They also may
be complicated enough (internally) for the concerns that Gordon mentioned
(keeping object networks alive, etc) to be an issue in practise.  However it
would also be unthinkable (for various reasons) not to make open DB connections
clean up by finalisation, where necessary.  Notice also that DB code can (in
some cases) place considerable strain on the finaliser thread since the code
may not be interactive (so no handy pauses to work in while the user thinks).
The end result of that is that you want to be able to turn off "finalisability"
in the clean-up code, or else you have to write extra code to ensure that the
cleaned-up but still finalisable object puts as little strain on the system as
possible.

The other example is about managing Windows GDI handles.  In this case the
resource to be managed is quite lightweight, and there's no great problem with
relying mostly on finalisation to clean-up (which simplifies the system very
considerably, or at least allows significantly greater flexibility for a given
degree of complexity).  What /is/ a problem is understanding how the handles
are managed, especially since some are "owned", and must be cleaned up, and
some are "shared" and must /not/ be cleaned up, but the two are otherwise
interchangeable.  In this case I think the biggest benefit of explicit control
of finalisation is just that: it /is/ explicit.  It makes it easier to
understand how that part of the system fits together.

   -- chris
John C. Bollinger - 22 Nov 2004 15:32 GMT
>>>Actually, I'd prefer to have beFinalizable() and beNotFinalizable() as
>>>(probably protected) methods of Object, and for "finalisability" to be
[quoted text clipped - 13 lines]
> allocation/deallocation under the control of the programmer has too many
> advantages to list ?

I think I'm coming more from the point of view that Java finalization is
inherently unsuited to so many kinds of tasks that I would prefer to not
offer additional hooks -- it would just make it that much easier to
write broken code.

In fact, I think I am shifting my stance on finalization in general from
"I don't know what it's good for" to "it isn't good for anything."
Objects may not be finalized within any particular time frame, or even
finalized at all, so finalization is fundamentally unsuited to managing
limited resources, and especially unsuited to managing resources whose
states persist beyond the end of program execution.  What, then, could
finalization be used for?  It has to be something that the program would
prefer to happen after an object becomes unreachable, but which it can
accommodate never happening.  I can only imagine some use related to
monitoring the GC process itself, but I reject that as something that
the program should not be concerning itself with.  I'm open to other
suggestions.

> My position is that finalization itself is a fairly "heavy-weight" operation,
> and as such is less well-suited to automation.  Mainly because there's more to
> loose when (or if) the system doesn't handle it as well as I/we could if we
> were doing it by hand.  (There's a definite parallel there with closing file
> handles, which are too heavyweight to be suitable for handling completely
> automatically -- by finalisation, for instance ;-)

I'll claim that as an argument in favor of my new position against
finalization in general.

> The other reason I favour the more explicit approach is that I work with it
> often and find it "feels" better (as I've mentioned before, I do more work in
[quoted text clipped - 14 lines]
> You might say that they form the skeleton of the design, and once you can see
> that clearly, then it's easier to see where the flesh fits around it.

At least for Java, that's a broken design paradigm.  If you need to be
certain that resources are released then you cannot depend on
finalization to do it.  In fact, the place where that paradigm makes the
most language-neutral sense is in the context of abnormal program
termination, where it might be expected to provide an alternative route
for cleaning up resources.  In Java, however, that is precisely the
scenario where it is _least_ likely that objects will be finalized.

You can in any case provide a very similar feature within Java by
placing a mutable "needsToBeFinalized" flag in your classes, and having
a finalize method that tests it as a condition for doing anything
(else).  In that I am now opposing using finalization for anything, I
won't advocate building that sort of thing into the language.

> I find it particularly helpful in cases where the object is normally cleaned up
> explicitly, but may also be handled by finalisation as a fall-back for when
[quoted text clipped - 4 lines]
> beFinalizable()/beNotFinalizable() and the whole thing then normally becomes
> crystal clear.

That sounds like a design issue to me.  If there is a complicated
cleanup sequence then it ought to be wrapped up in some method.  You'll
need that anyway if you want the finalizer to be able to clean up
properly.  If you can wrap it up in a method, then you can invoke that
method wherever you might invoke beNotFinalizable().  Am I missing
something here?

>>Do you have a concrete-ish example of how your version of finalization
>>management would be an improvement over what Java already offers?
[quoted text clipped - 9 lines]
> would also be unthinkable (for various reasons) not to make open DB connections
> clean up by finalisation, where necessary.  Notice also that DB code can (in

In Smalltalk perhaps that scenario would be unthinkable, but in Java you
cannot count on the connection being finalized anyway, so you need to
rely on the connection user to clean it up.  You _could_ write cleanup
code into a finalizer, and that might rescue some broken programs, but
it might also disguise the problems in such programs.  I would rather
have my program fail sooner and more consistently.

> some cases) place considerable strain on the finaliser thread since the code
> may not be interactive (so no handy pauses to work in while the user thinks).
> The end result of that is that you want to be able to turn off "finalisability"
> in the clean-up code, or else you have to write extra code to ensure that the
> cleaned-up but still finalisable object puts as little strain on the system as
> possible.

That sounds like an issue that could be handled by appropriate coding of
the finalize() method, if you're going to rely on finalization at all.
The difference between Java providing a feature to bypass the finalize()
method and the programmer providing a feature to toggle finalize()
between "do something" and "do nothing" is insignificant as far as I can
see.  I'd relegate the feature to the "syntactic sugar" category.  Of
course, these days it seems that items in that category have a
reasonably good chance of being implemented....

> The other example is about managing Windows GDI handles.  In this case the
> resource to be managed is quite lightweight, and there's no great problem with
[quoted text clipped - 6 lines]
> of finalisation is just that: it /is/ explicit.  It makes it easier to
> understand how that part of the system fits together.

It seems to me that handling resources such as these demands classes
that understand the resources better, rather than classes that require
the user to manipulate instances correctly, for some varying definition
of "correctly".  You might not need distinct classes for "owned" and
"shared" handles, but you could at least provide an internal flag to
distinguish instances with respect to that characteristic.  The objects
ought to encapsulate the knowledge of how they need to be cleaned up,
and provide a uniform face to users.

So, then, I guess we do have to agree to disagree.  I am not persuaded
by your examples, and I doubt whether you have been persuaded by my
commentary on them.  Particularly as you have raised personal preference
and style as a contributing factor, I have no reason to expect to change
your mind.  (And, for the record, I feel no special need to do so.)

John Bollinger
jobollin@indiana.edu
Carl Howells - 16 Nov 2004 17:50 GMT
> BTW, don't forget that /not/ relying on finalisation can have costs too.  More,
> and more complicated, code.  More opportunity for error.  Even, potentially
> larger object networks -- e.g. if an object that may need cleanup cannot just
> be handed-over to another context and forgotten, then the recieving context may
> have to keep a link back to the supplier so that it can "hand back" the object
> when it has finished with it.

Cleanup of non-memory resources can be done with a PhantomReference and
ReferenceQueue combination, with much simpler semantics than those of
finalization.  After all, there's no chance of object resurrection with
that system, meaning that the cleanup *will* only be done once.

It is slightly more difficult to implement than just overriding a
finalize method, admittedly...  But I think it's also conceptually more
elegant.

Oh, and while I'm replying to you, I suspect your interpretation of my
test results earlier in this thread was accurate..  Objects which need
to be finalized just have to stick around for an extra GC cycle,
delaying their collection somewhat, but no real bias exists.
Chris Uppal - 20 Nov 2004 14:21 GMT
> Cleanup of non-memory resources can be done with a PhantomReference and
> ReferenceQueue combination, with much simpler semantics than those of
[quoted text clipped - 4 lines]
> finalize method, admittedly...  But I think it's also conceptually more
> elegant.

Fair enough, though I don't share that opinion.

To me it seems like essentially the same thing (introspection on objects'
lifetimes) packaged more indirectly (and somewhat more confusingly).  I'll
admit, though, that that may be more an artefact of Sun's /specific/ design
(and poor documentation), than inherent in the idea of reference queues itself.
Maybe I'll warm to 'em yet...

   -- chris
Stefan Schulz - 09 Nov 2004 18:52 GMT
> What else can I do to make sure that cleaner has finished without  
> freezing my UI.

Since you are shutting down anyway, take a look at  
Runtime.addShutdownHook()

Signature

Whom the gods wish to destroy they first call promising.



Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.