2

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

在谈到没有自己的取消策略但调用可以被中断的方法的方法的部分中,本书有以下内容要说。

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

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

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

谁能解释为什么应该这样做?

4

4 回答 4

4

我在我的方法中调用 Thread.sleep,我将不得不在循环中调用它或其他什么?

Thread.sleep()InterruptedException当当前线程被中断(被另一个线程)时会抛出一个。如何应对是你的选择。如果你想睡觉,不管是否有人试图打断你,那么是的,你必须在 try-catch 块周围建立某种循环。可能您应该使用时钟(例如System.nanoTime())来检查在引发异常之前您睡了多长时间,然后继续睡眠剩余时间等。

请注意, 当另一个线程通过调用中断当前线程时才InterruptedException抛出. 它不会自行发生,因此通常您不需要围绕 sleep 或类似的东西构建任何循环。通常线程被中断只有一个很好的理由(例如应用程序关闭),所以你可能想要支持取消/中断,除非没有特殊的理由不这样做。例如,“特殊原因”可能是写入 I/O 设备并尝试保证将写入所有数据,而不管取消尝试如何。(current)Thread.interrupt()

于 2011-10-25T07:13:42.233 回答
2

先解释一下:

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

如果可中断操作(如Object.wait()or 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();
    }

  }

此代码尝试从 0 到 10 计数 x。如果没有中断,它将完成并输出“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 ,完成我们的任务,然后返回。但是,这不是上面提到的良好做法,并且在某些情况下可能会导致麻烦。

于 2011-10-27T13:48:04.420 回答
0

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

调用阻塞的方法意味着,当前执行被阻塞并等待直到阻塞方法返回一个值。这可以在一个循环中完成。然后您就知道方法调用是否成功或调用的方法是否被中断。

于 2011-10-25T07:10:14.253 回答
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")
}

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

于 2011-10-25T07:10:27.467 回答