ARM and thread interruption
Mike Clark
mclark at apache.org
Mon Jun 28 22:36:46 PDT 2010
On Mon, Jun 28, 2010 at 7:44 PM, Carlos Costa e Silva <carlos at keysoft.pt> wrote:
> -----Original Message-----
> From: Mike Clark [mailto:mclark at apache.org]
> Sent: terça-feira, 29 de Junho de 2010 00:47
> To: coin-dev at openjdk.java.net
> Subject: ARM and thread interruption
>
> I am little concerned about ARM suppressing
> java.lang.InterruptedException ...
> --------------------------
>
> Hmm, and how is that different from what happens now?
Well, you're right. ARM is -- as currently specified -- not too much
different with regards to interrupt handling than a naively written
try/finally. My original phrasing may have made it sound like ARM
could cause a problem that doesn't exist today with try/finally. This
is not true, and I'm sorry if I was misleading.
However, I think that -- just like ARM can help us write correct
try/finally constructs for resource cleanup -- ARM can also help us
write code that correctly and reliably preserves interrupt status on a
thread.
Your code:
> try {
> // wait until interrupted
> } finally {
> throw RuntimeException("Oops, InterruptedException thrown away");
> }
Could be modified in this way:
boolean interrupted = false;
try {
// wait until interrupted
} catch(InterruptedException ioe) {
interrupted = true;
} finally {
try {
throw RuntimeException("exception thrown from finally," +
" but interrupt status will be preserved");
} finally {
if (interrupted) {
Thread.currentThread().interrupt();
}
}
}
This code may seem ugly and obtuse. But I have written code like this
before to improve reliability and speed of interrupt processing.
Assume ARM is a macro for a properly written try/finally construct.
The question becomes: does a properly written try/finally construct
preserve thread interrupt status? I think it should.
> In fact adding behavior (this restoring the interrupt flag) to ARM
> suppression handling is counter-intuitive making ARM blocks behave very
> different from traditional try/finally blocks where no such handling is
> done.
Point taken. But then again ARM already behaves significantly
differently from traditional try/finally: Under ARM, an exception in
an ARM block is thrown in favor of an exception in the cleanup block.
This is the opposite of traditional try/finally, where an exception in
the finally will be thrown in favor of an exception in the try. So I
am not sure if "different from traditional try/catch" is a major
strike against.
> Or am I missing something here (quite possible :) ?
While I feel strongly that interrupt statuses should always be
preserved until handled by policy-setting code, not everyone may share
this viewpoint. I do not think this is a cut-and-dry issue. However,
all the best-practice material I have read (e.g. [1]) strongly
suggests that code which does not set the interruption policy for a
thread, should -- upon receiving an InterruptedException -- either
re-throw the exception to code which implements the thread's
interruption policy, or if unable to do that (as in the case of ARM),
re-assert the interrupt status on the thread.
[1] "A task should not assume anything about the interruption policy
of its executing thread unless it is explicitly designed to run within
a service that has a specific interruption policy. Whether a task
interprets interruption as cancellation or takes some other action on
interruption, it should take care to preserve the executing thread's
interruption status. If it is not simply going to propagate
InterruptedException to its caller, it should restore the interruption
status after catching InterruptedException" -Java Concurrency In
Practice, section 7.1.2
In fairness, it seems entirely possible for a programmer to devise a
strategy which uses ARM and also preserves interrupt status:
try {
try (Resource r = new Resource()) {
r.methodThatMightThrowInterruptedException();
}
} catch (Exception e) {
// Re-assert interrupt flag if an InterruptedException was suppressed
for(Throwable ex : e.getSuppressedExceptions()) {
if (ex instanceof InterruptedException) {
Thread.currentThread().interrupt();
break;
}
}
// OK now we can throw the main ARM exception
// (might be some trouble with losing compatibility
// with method's throws clause)
throw e;
}
And maybe this whole situation is so niche that we should let
programmers implement the above by hand, when they anticipate that
interruption will be used with their code.
But if we can agree that such preservation of interrupt status is
almost universally desirable (which I believe it is), then why not
build the preservation of interrupt status into the ARM template
itself?
Some reasons for keeping it out are:
1) The overhead of tracking interrupt status for all ARM blocks might
be considered too high
2) There are important enough or numerous enough cases where
re-asserting the interrupt would for some reason be undesirable
3) It deviates too far from traditional try/finally (the danger there
being that programmers intuitively expect one thing, but get
another, thus possibly leading to misunderstandings and mistakes)
4) It complicates ARM too much, or is outside the scope of ARM
And I would answer:
1) The overhead should be minimal. But that must perhaps be weighed
against the fact that this whole scenario is an edge-case:
a) interruptions must be in use, and
b) the interrupt must timed such that it arrives during resource
cleanup, and
c) the cleanup block must contain resources that actually throw
InterruptedException out of .close()
Only under these conditions would ARM interrupt-tracking result in
anything additional happening. Is the overhead introduced into every
ARM block worth the correctness in this edge case?
2) I do not know of any cases where preserving the interrupt status
would be undesirable
3) I think that this issue may be so obscure that the vast majority of
programmers do not have any behavioral expectations, and thus there
is not a great deal of risk in violating those expectations
4) Subjective
> Carlos
thanks for your feedback, Carlos
Mike
More information about the coin-dev
mailing list