Java try finally variations
This question nags me for a while but I did not found complete answer to it yet (e.g. this one is for C# 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:
- InterruptedException (e.g. via Thread#interrupt()) or OutOfMemoryError exception is thrown
- JVM exits (e.g. via kill, System.exit())
- 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/JV开发者_运维百科M specs that support the answers.
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.
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: Is this a safe way to release resources in Java?
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.
精彩评论