5

In business scenario, InterruptException occurs multiple times, some before the business code is executed, and some after the business code. How to deal with InterruptException makes me confused.

     1. preBusiness code semaphore.acquire()

        try {
            semaphore.acquire();
        } catch (InterruptedException e) {
           // do something
        }
        resObj = caller.stepTry();
        semaphore.release();
  1. postBusiness code latch.await(), service.take().get()

    CompletionService<CallableResultBO> service = new ExecutorCompletionService<>(executor);
    CountDownLatch latch = new CountDownLatch(size);
    
    for (R callable : listCall){
        callable.setCountParam(JdkThreadCountBO.buildByLatch(latch));
        service.submit(callable);
    }
    
    try {
        latch.await();
    } catch (InterruptedException e) {
        // do something
    }
    
    CallableResultBO[] resArr = new CallableResultBO[size];
    for ( int i = 0; i < size; i++ ){
        try {
            resArr[i] = service.take().get();
        } catch (InterruptedException e) {
            // do something
        } catch (ExecutionException e) {
            // do something
        }
    }
    

    There are also some doubts found in practice, and I am still thinking about how to draw conclusions.      A thread can't be interrupted casually. Even if we set the interrupt state for the thread, it can still get the CPU time slice. Usually only threads blocked by the sleep() method can immediately receive an InterruptedException, so in the case of a sleep interrupt task, you can use try-catch to jump out of the task. In other cases, it is necessary to determine whether the task needs to be jumped out (Thread.interrupted() method) by judging the thread state.

         In addition, the code modified by the synchronized method will not be interrupted immediately after receiving the interrupt signal. The synchronization code of the ReentrantLock lock control can be interrupted by InterruptException.

刘海翔
  • 61
  • 1
  • 3
  • If I have time I'll write up a comprehensive answer later, but the definitive answer to this question is to read JCiP, the book *Java Concurrency in Practice* by Goetz et al, which addresses this question at length. – Daniel Pryden Oct 04 '18 at 02:15
  • Thank you for your reply. I am now responsible for an order fulfillment center, often writing concurrent code, and often encounter this exception. I have seen both the book and the discussion, but some of my doubts have not been solved. Although Thread.sleep() can throw this exception, it is not representative for testing this exception. Compared with the "deep java principle", I need to explore the best practices of this exception from a business perspective. – 刘海翔 Oct 04 '18 at 03:25
  • I'm not sure I understand what you're asking, or the difference between "deep Java principle" and "best practices". If you don't understand what the exception *means*, the code you write won't be best practice. `InterruptedException` means "I was doing something that involved waiting, but someone told me to hurry up and stop waiting, so I didn't finish doing the thing that involved waiting". The right way to handle an `InterruptedException` depends entirely on what was happening that involved waiting and who could possibly have interrupted it. – Daniel Pryden Oct 04 '18 at 20:07

2 Answers2

6

Generally, you are advised to do the following:

    void methodThatWaits()
    {
        try 
        {
            Thread.sleep( 1000 );
        }
        catch( InterruptedException e )
        {
            //e.printStackTrace();
            Thread.currentThread().interrupt();
        }
    }

So, no, Thread.currentThread().interrupt(); is not redundant.

This is known as the Java Thread.currentThread().interrupt idiom, and it is explained in detail in Java Concurrency in Practice, Chapter 7.1.3. It is also mentioned in Effective Java, you can read an excerpt here: Google Books - Effective Java - search for java idiom thread interrupt interruptedexception josh bloch

Mike Nakis
  • 56,297
  • 11
  • 110
  • 142
4

All the java.util.concurrent classes use interruption uniformly, to indicate that the receiving thread should wind up what its doing and terminate. It seems to me it only makes sense to follow the same guidelines when writing code that uses these classes.

When something throws InterruptedException the interrupt flag for that thread is cleared. Calling Thread.currentThread().interrupt restores the flag to its previous value.

For toy examples in tutorials restoring the flag seems stupid, because it’s in a catch block at the end of a run method and the thread is terminating immediately anyway. The point is that there may be many layers of things going on within a thread, you may have a Runnable task submitted to a threadpool where that task is talking to a blocking queue, etc., where every participant needs to know if an interrupt occurs so they can all arrive at a stopping point and finish gracefully. If any one of these eats the InterruptedException without restoring the flag, somebody may miss hearing about the interrupt, the thread will keep on working, and your application may not quit cleanly.

Not finishing cleanly can mean:

  • There may be half-done work hanging out to dry as a result.

  • Threads are GC roots, so you may get a memory leak.

  • Any non-daemon thread that stays alive keeps the JVM from exiting.

For what to do with InterruptedException: Synchronizers in java.util.concurrent tend to let it be thrown. Whether you do that or not depends on what you need to do to finish things up. Thread cancellation is voluntary so that you can make sure your task gets cleaned up reliably.

Nathan Hughes
  • 94,330
  • 19
  • 181
  • 276