How to handle InterruptedException that cannot be passed to the client?

I came across a situation where I have to deal with InterruptedException , but I can not pass it up and I do not feel that my code should be allowed to internalize it. To be precise, I am working on the implementation of distributed locking, and the service support request may be interrupted or even time out - and, of course, java.util.concurrent.Lock does not take into account such cases and does not allow me to spit out InterruptedException. I'm struggling to write the correct implementation for the non-throwing methods lock() , tryLock() and unlock() .

So the question is, what would be the right strategy to handle such a case? From the current point of view, I see only three options (and I smell for each of them):

  • Ignore the thrown exception in the lock / tryLock / unlock methods, repeat / return false / provided that even if the request did not reach it, TTL will eventually unlock the entry. This is obviously not the best solution, because it hopes that everything will be fine and not solve problems.
  • Wrap a RuntimeException in the heir. This seems to be a terrible decision too, since the client code should work with a specific implementation, and not with the original interface, and the exception thrown, of course, was not made for this purpose.
  • Use call force Thread.currentThread().interrupt() . I do not like this method because it basically tells the thread to process its own interrupt, rather than sending a notification about the interruption of the call; also, as I understand it, if there is no external polling, it will eventually make a thread, but will not instantly handle the interrupt, possibly in a completely different place.

(And, of course, there is an option that allows the client code to customize the desired behavior, but this still does not give me a really good solution)

Is there a better way than I described? And if not, which one should be preferable to others?

+5
source share
3 answers

Let me discuss each of your options available.

  • Ignore Aborted Exception

It is not right. There is never the right to swallow an exception when you implement something like a library that other users will rely on. In these cases, it would never be prudent to swallow an exception unless you are distributing it as another exception that provides more meaningful information to the client. InterruptedException is basically a request to cancel a thread, and this information should never be suppressed from the client, regardless of whether the lock will be unlocked later. The client should know that someone wants the running part of this thread to be stopped.

  1. Wrap a RuntimeException

No. This is wrong for the same reason as above. the reason for the distribution of InterruptedException is to inform the client that a request was made to cancel the executable thread and, therefore, its packaging in RuntimeException is incorrect because this information is lost.

  1. Use / force Thread.currentThread().interrupt() call

This may be right or wrong depending on the use case. Ask yourself if you would be good at throwing InterruptedException.

  • If this is normal (this is not in your case, but), you can state that your method throws an InterruptedException and allows callers to worry about what needs to be done. This usually happens when you call a method (say operation() ) that throws an InterruptedException , and you cannot continue if this call does not end. Assume operation() throws an InterruptedException , then you can do nothing but throw this exception. Therefore, you should not catch the exception. In this case, just declare that your method throws an InterruptedException and you are done

  • If this is not good, then the correct way to handle this would be to force the interrupt() call. Using this, you suppress the exception, but you still give the client the opportunity to check the flag to see if there was an interrupt request. And you are right. This requires client polling, not interrupt handling. But this is not so. If you do not want customers to poll, then propagating this exception would be a better option. But this is not always possible, and your example is one such use case. And there are many cases where a thread of execution can return some meaningful information, even when it is interrupted. Therefore, in this case, the exception is suppressed, but information that there is a request for completion can be passed above by calling the interrupt() method. Thus, the client can either simply use the result that was returned from the partial calculation or the poll to check whether the interrupt flag was set depending on the use case. Thus, you provide the customer with great flexibility by doing this.

+3
source

For me, the answer is almost always 3.

Java uses a mutual interrupt model: it seems like a very British approach to me:

I say, old guy, could you stop what you are doing if it’s not too much trouble?

But there is no reason to act in a timely manner (or, indeed, in general) to interrupt. To use a quote from Robin Williams :

Stop! ... or ... I'll say it again!

You can write your code to check interrupts periodically, or not - it would be very dirty and repetitive if you would do it everywhere. But if you do not want to do anything when you are interrupted, you should at least preserve the fact that an interrupt has occurred so that the call code that wants to do something acts accordingly.

There is nothing special about InterruptedException - it is a literally empty subclass of Exception . Usually this is only thrown in the first place if a particular method checks Thread.interrupted() or .isInterrupted() . Thus, I would not worry that calling interrupt() does not immediately cause the thread to stop what it is doing - this is the very nature of cooperative interruption.


To determine why I say “almost always” above: the Java tutorial describes the interrupt in this way:

An interrupt is an indication of a thread that should stop what it is doing and do something else. It is up to the programmer to determine exactly how the thread responds to an interrupt, but very often the thread ends.

I only very, very rarely did anything other than wanting to stop interrupting the flow.

If I wanted the thread to "do something else," I would most likely use the executing service: each of the "things" to be done represents a separate Runnable , so I don’t even know if they are done anyway in the same thread.

Therefore, I usually interrupt the thread and then throw a RuntimeException :

 catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException(e); } 

Each Runnable simply finishes what it does when it is interrupted; the contractor’s service decided whether to perform another task.

This is mainly only when writing framework level code (e.g. ExecutorService), which I would prefer to continue after interruption.

+2
source

It depends entirely on your application, in particular on the value of InterruptedException in your thread.

Option 1 is bad practice for me: relying on other mechanisms, your code is fuzzy and scary. You can always catch the exception and use only the finally method to free all locked resources.

Then restarting the exception or hiding it (possibly returning a specific result) is up to you and the specific value that this exception has in your application.

+1
source

Source: https://habr.com/ru/post/1247769/


All Articles