views:

220

answers:

3

This question nags me for a while but I did not found complete answer to it yet (e.g. this one is for C# http://stackoverflow.com/questions/463029/initializing-disposable-resources-outside-or-inside-try-finally). Consider two following Java code fragments:

Closeable in = new FileInputStream("data.txt");
try {
    doSomething(in);
} finally {
    in.close();
}

and second variation

Closeable in = null;
try {
    in = new FileInputStream("data.txt");
    doSomething(in);
} finally {
    if (null != in) in.close();
}

The part that worries me is that the thread might be somewhat interrupted between the moment resource is acquired (e.g. file is opened) but resulting value is not assigned to respective local variable. Is there any other scenarios the thread might be interrupted in the point above other than:

  1. InterruptedException (e.g. via Thread#interrupt()) or OutOfMemoryError exception is thrown
  2. JVM exits (e.g. via kill, System.exit())
  3. Hardware fail (or bug in JVM for complete list :)

I have read that second approach is somewhat more "idiomatic" but IMO in the scenario above there's no difference and in all other scenarios they are equal.

So the question:

What are the differences between the two? Which should I prefer if I do concerned about freeing resources (especially in heavily multi-threading applications)? Why?

I would appreciate if anyone points me to parts of Java/JVM specs that support the answers.

A: 

My view is that is when you are working with a managed runtime, such as Java or .NET you really should not (and it's good!) concern yourself with things like your particular question. Only because you are completely disconnected from the underlying operating system and its native APIs. All you have to know is that you call Closable.close() in your finally block and your resource will always be freed.

Strelok
as long as you acquired the resource in the try block...
pgras
Unfortunately "managed" means that it solves only part of resource management problems (though a sizeable one). If you aquire lot of resources you still should take care of releasing them since there's usually limited amount of them. And yes, there are locks. And deadlocks.
Petr Gladkikh
@pgras Why would you want to acquire the resources in the `try` block?? That just makes a mess of your code.
Tom Hawtin - tackline
@Tom To be precise you have to enter the try block to guarantee that the finally block will be called (you may get an exception before entering the try block). The easy way to guarantee it is to acquire the resource(s) inside the try block.
pgras
+4  A: 

a) Note that interrupting the thread with interrupt() will not take effect immediately, and may not have any effect at all, if the thread being interrupted does not cooperate. There is no way the thread will exit due to interrupt() during the execution of :

Closeable in = new FileInputStream("data.txt");

The only thing that will happen is that its interrupted flag of the thread will be turned on.

b) regarding OutOfMemoryError - I don't see how it can occur right after the construction of the input stream. It may occur in another thread, but this will have no immediate effect on this thread. The problem with OutOfMemoryError, is that your finally block may also fail, because there is not enough memory to complete it...

c) The only way I know that a thread can be interrupted aggressively is using the deprecated methods Thread.stop() and Thread.stop(Throwable). See a similar discussion here: http://stackoverflow.com/questions/2708229/is-this-a-safe-way-to-release-resources-in-java/2708270#2708270

Eyal Schneider
+5  A: 

I don't think there is any reason to be concerned:

1) InterruptedException (e.g. via Thread#interrupt())

Calling Thread.interrupt() does not cause InterruptedException to be thrown spontaneously. The exception is only thrown within specific (and well documented) blocking methods; i.e. blocking I/O and synchronization methods. This exception cannot be thrown after returning from the stream constructor and before entering the try block.

or OutOfMemoryError exception is thrown

If an OutOfMemoryError is thrown, you cannot guarantee full recovery of the underlying file descriptor, no matter where you put the stream constructor. You should never attempt to recover from an OOM, so the question of whether the stream is closed is moot. Besides, this exception is only thrown on a thread that is actually attempting to allocate memory, and that is not happening at this point.

2) JVM exits (e.g. via kill, System.exit())

If the application is being forcibly terminated by an external kill or a System.exit() call, it does not matter if streams are closed properly. Besides, in both cases there is no guarantee that finally clauses will be executed.

3) Hardware fail (or bug in JVM for complete list :)

All bets are off. You have no way of knowing if anything will execute, let alone the finally blocks.

There is one more situation where a thread might receive an spontaneous exception at that point, with some (naive) expectation that it might recover. That is when some misguided programmer decides to call the deprecated Thread.stop() method. You might think that putting the stream constructor call inside the try block would help. But actually it won't, because the ThreadDeath exception could be raised inside the stream constructor between opening the underlying file and completing construction of the stream object. So the FD could leak anyway.

This is just one reason why Thread.stop() is deprecated. Don't use it.

Stephen C