A lot of Java resource usage examples look like this:
Resource r = openResource();
try {
// use resource
} finally {
r.close();
}
The declaration of r
has to be outside of the try
-clause to be visible in the finally
-clause, but this also makes it look like there's a potential race condition: what if there's a thread interruption right between the openResource()
-call and entering the try
-clause?
Could that mean that the resource doesn't actually get closed in that scenario?
Or does Java guarantee that the try-finally
covers r
"fully", despite the syntax looking like it wouldn't?
Or do I have to write:
Resource r = null;
try {
r = openResource();
// use resource
} finally {
if (r != null) r.close();
}
in order to protect against thread interruptions?
what if there's a thread interruption right between the openResource()-call and entering the try-clause?
Then the thread won't throw an InterruptedException
until it hits some blocking call. That can't happen before it gets into the try
block, because there aren't any more blocking calls, assuming the method actually returns. From the docs for InterruptedException
:
Thrown when a thread is waiting, sleeping, or otherwise occupied, and the thread is interrupted, either before or during the activity. Occasionally a method may wish to test whether the current thread has been interrupted, and if so, to immediately throw this exception.
Note that even if you do put the acquisition inside the try
block, that doesn't really prevent any race condition that would otherwise exist - because you'd be relying on the method or constructor returning in the first place. If an exception can happen after the method/constructor returns, why can't it happen just before it returns, but after the resource has been acquired? If that happens, there's nothing you can call close
on...
I'd still recommend using the try-with-resources statement in Java 7, but if you look at the JLS section 14.20.3.1 you'll see that the expansion is like your first piece of code:
The meaning of a basic try-with-resources statement:
try ({VariableModifier} R Identifier = Expression ...) Block
is given by the following translation to a local variable declaration and a try-catch-finally statement:
{ final {VariableModifierNoFinal} R Identifier = Expression; Throwable #primaryExc = null; try ResourceSpecification_tail Block catch (Throwable #t) { ... #primaryExc = #t; throw #t; } finally { ... } }
See more on this question at Stackoverflow