处理InterruptedException的最佳实践

时间:2018-10-03 08:08:52

标签: java exception concurrency

在业务场景中,InterruptException多次发生,某些发生在业务代码执行之前 ,而某些发生在业务代码之后一些。如何处理InterruptException使我感到困惑。

 1. preBusiness代码 semaphore.acquire()

        try {
            semaphore.acquire();
        } catch (InterruptedException e) {
           // do something
        }
        resObj = caller.stepTry();
        semaphore.release();
  1. 邮递区号 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
        }
    }
    

    在实践中还存在一些疑问,我仍在思考如何得出结论。 线程不能随意中断。即使我们为线程设置了中断状态,它仍然可以获得CPU时间片。通常,只有被sleep()方法阻塞的线程才能立即收到InterruptedException,因此,对于睡眠中断任务,可以使用try-catch跳出任务。在其他情况下,有必要通过判断线程状态来确定是否需要跳出任务(Thread.interrupted()方法)。

    此外,通过同步方法修改的代码不会在收到中断信号后立即被中断。 ReentrantLock锁定控件的同步代码可以被InterruptException中断。

2 个答案:

答案 0 :(得分:2)

通常,建议您执行以下操作:

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

因此,不,Thread.currentThread().interrupt();不是多余的。

这被称为Java Thread.currentThread()。interrupt习惯用法,在 Java Concurrency in Practice (第7.1.3章)中对此进行了详细说明。 有效的Java 中也提到了此内容,您可以在此处阅读摘录:Google Books - Effective Java - search for java idiom thread interrupt interruptedexception josh bloch

答案 1 :(得分:2)

所有java.util.concurrent类均统一使用中断,以指示接收线程应结束其工作并终止。在我看来,编写使用这些类的代码时遵循相同的准则才有意义。

当某些东西抛出InterruptedException时,该线程的中断标志将被清除。调用Thread.currentThread()。interrupt会将标志恢复为其先前的值。

对于教程中的玩具示例,恢复标志似乎很愚蠢,因为它位于run方法末尾的catch块中,并且线程无论如何都立即终止。关键是线程中可能有许多事情在进行,您可能有一个Runnable任务提交到了一个线程池,在该线程中该线程正在与阻塞队列进行对话,等等,每个参与者都需要知道是否发生中断这样他们都可以到达停靠点并优雅地完成比赛。如果其中任何一个在不恢复标志的情况下吃了InterruptedException,则可能有人会错过有关中断的消息,线程将继续工作,并且您的应用程序可能无法干净退出。

整理不干净可能意味着:

  • 可能有半完成的工作挂在外面晾干。

  • 线程是GC的根,因此可能会发生内存泄漏。

  • 任何保持活动状态的非守护程序线程都可以防止JVM退出。

关于InterruptedException的处理方法:java.util.concurrent中的同步器倾向于抛出该异常。是否执行此操作取决于完成操作所需执行的操作。线程取消是自愿的,因此您可以确保可靠地清理任务。

相关问题