Java:从代码中调用可中断的方法

时间:2011-10-25 06:45:49

标签: java multithreading concurrency interrupted-exception

我正在阅读Java Concurrency in Practice的第7章。

在一个部分讲述了没有自己的取消政策的方法,但是调用了可以被闯入的方法,这本书有以下几点要说。

  

不支持取消但仍称为可中断的活动           阻塞方法必须在循环中调用它们,然后重试           检测到中断。在这种情况下,他们应该保存           本地中断状态,并在返回之前恢复,           而不是立即捕获InterruptedException。

我还没有完全理解这一点。

这是不是意味着,如果我在我的方法中调用Thread.sleep,我将不得不在循环中调用它?

任何人都可以解释为什么要这样做吗?

4 个答案:

答案 0 :(得分:4)

  

我在我的方法中调用Thread.sleep,我将不得不在循环中调用它?

当前线程被中断(由另一个线程)时,

Thread.sleep()将抛出InterruptedException。你可以选择如何应对。如果你想睡觉,无论是否有人试图打断你,那么是的,你必须围绕try-catch块构建某种循环。可能你应该使用一个时钟(例如System.nanoTime())来检查你在抛出异常之前睡了多长时间,然后继续睡觉剩下的时间等等。

请注意,如果另一个线程通过调用InterruptedException打断了当前线程,则(current)Thread.interrupt() 。它本身不会发生,所以通常你不需要在睡眠或类似的东西周围建立任何循环。通常线程仅在有充分理由(例如应用程序关闭)的情况下被中断,因此您可能希望支持取消/中断,除非没有特殊原因不这样做。例如,“特殊原因”可能是写入I / O设备并尝试保证所有数据都将被写入,而不管取消尝试。

答案 1 :(得分:1)

首先解释一下:

线程的中断状态基本上是一个布尔标志,由interrupt()设置为“true”。 此标志的当前状态可以使用Thread.currentThread().isInterrupted() 读取

如果可中断操作(如Object.wait()Thread.sleep())发现设置了中断标志 它将抛出一个InterruptedException并同时清除(设置为“false”)标志,它可能如下所示:

if ( Thread.interrupted() ) { throw new InterruptedException(); }

注意并记住Thread.interrupted()隐式清除中断的旗帜! 这意味着,当您执行catch( InterruptedException ie) {...}时, 线程本身不知道它已经被打断了。

那就是说,让我们看看两个例子:

首先是支持取消的任务示例。 在这里,我们并不关心任务在中止之前的进展程度:

  public void run() {

    int x = 0;

    try {

      while (x < 10) {
        Thread.sleep(1000); // Some interruptible operation
        x++;
      }

      System.out.println("x = " + x);

    } catch (InterruptedException ie) {

      System.out.println("Interrupted: x = " + x);

      // We know we've been interrupted. 
      // Let the caller know it, too:
      Thread.currentThread().interrupt();
    }

  }

此代码尝试将x从0计数到10.如果它没有被中断,它将完成并输出“x = 10”。 但是,如果线程在两者之间中断,则会抛出InterruptedException,中止正在进行的递增x的任务。 在这种情况下,输出可以是从“Interrupted:x = 0”到“Interrupted:x = 9”的任何内容,具体取决于线程何时被中断。

请注意,从退出之后恢复线程的中断标志被认为是一种好习惯 否则,此run()方法的调用者将看不到中断状态。

现在,如果我们的任务完全执行至关重要,那么输出将始终为“x = 10”,这意味着任务不支持取消,我们需要另一种方法:

  public void run() {
    int x = 0;

    boolean wasInterrupted = false; // <- This is the local variable to store the interruption status

    while (x < 10) {

      wasInterrupted = wasInterrupted || Thread.interrupted(); // not really needed in this case, but for the sake of completeness...

      try {

        Thread.sleep(1000); // <- Some interruptible operation

      } catch (InterruptedException e) {
        wasInterrupted = true;
      }

      x++;
    }

    System.out.println("x = " + x);

    if ( wasInterrupted ) {
      Thread.currentThread().interrupt();
    }

  }

在这种情况下,我们甚至在InterruptedException之后继续处理,直到任务完成。 为了保持良好状态,如果我们检测到中断,我们会将该条件存储在wasInterrupted中,以便我们可以 在从方法返回之前正确设置中断标志。

这就是

的含义
  

应该在本地保存中断状态,并在返回之前恢复它。

它说“应该”,因为我们并不是严格要求以这种方式处理中断 - 我们也可以忽略任何InterruptedException 并完成我们的任务,然后返回。不过,这不是上面提到的好习惯,在某些情况下可能会造成麻烦。

答案 2 :(得分:0)

据我所知:长期运行的服务本身不能或不应该被中断,它正在调用其他可以被中断的方法。因此,这个长期运行的服务应该能够检测到这一点并通过方法或标志报告它。但它应该能够再次尝试操作,而不是仅抛出InterruptedException。

要调用阻止方法的方法,当前执行将被阻止,并等待阻塞方法返回值。这可以循环完成。您知道方法调用是否成功或者调用的方法是否被中断。

答案 3 :(得分:0)

我没有这本书。但据我所知,如果一个活动中断(睡眠不是一个中断信号。但你可以通过中断信号从睡眠中唤醒一个线程),活动需要按顺序保存它的当前动态数据(中断状态)恢复自己并从以前的状态恢复。例如;

//Let's say you have integer data named "a"...
a = 45646;

//Normally after interruption, and terminating the activity data a is currently
//referencing @memory will be released...

//If you want to continue using data in a you have to save it somewhere
// persistant(Let's say a file)
void onInterruptionDetected()
{
    saveToSomeFile(a, "temp.txt");
}

//After re-execution of activity(Assuming we need a's previous data in order to 
// continue...), we can recover a's data(which is 45646) in previous interruption...
void onResumeDetected()
{
    a = loadFromFile("temp.txt")
}

希望这会有所帮助,我仍然困倦可能会有错误:)