Java 并发实践中的 "Using interruption for cancellation" 是否有拼写错误
Is there a typo in "Using interruption for cancellation" in Java Concurrency in Practice
在书中,Java Brian Goetz 等人的并发实践,第 141 页的示例 (2006):
7.5: Using interruption for cancellation.
class PrimeProducer extends Thread {
}
...
public void cancel() { interrupt(); }
令人困惑的是,书中指出线程应实施 中断策略,而可运行/可调用任务应实施取消策略.
然而这里我们在 Thread 对象中使用了一个 cancel()
方法。 这是怎么回事?几页之前,用 cancel()
给出了一个带有 Runnable 的例子 (7.1)。对于任务,我希望看到这样的合格 interrupt()
:
public void cancel() { Thread.currentThread().interrupt(); }
额外的、半相关的信息
我正在使用 ExecutorService,所以我处理任务(不是线程——ExecutorService 的线程工厂除外),但我找不到任何可能的 ExecutorService 完全关闭(许多线程)的示例这本书。
我启动和停止任务的方法是:
Map<CancellableRunnable, Future<?>> cancellableFutures = new HashMap<>(); // keep track of refs to tasks for stop()
public void init() {
Future<?> future = myExecutorService.submit(myTask);
cancellableFutures.put(myTask, future);
}
public void stop() {
for (Future task : cancellableFutures.values()) {
task.cancel(true); // also a confusing step. Should it be cancel() on Future or cancel() on task (Runnable/Callable)?
}
}
要正确关闭一个线程,您必须通过调用 thread.interrupt()
要求它自行关闭并且该线程应定期检查 thread.isInterrupted()
方法。
在 official documentation 中查看更多详细信息。
对于您的示例,您有一个 ExecutorService myExecutorService
。要关闭所有提交的线程(以及 线程池 本身),您可以调用 myExecutorService.shutdown()
。结果,线程池为所有线程调用 thread.interrupt()
。
要仅停止所需的线程,请正确调用 future.cancel(true)
。在这种情况下,您的 线程池 将处于活动状态并且能够提交另一个任务。
In the case of tasks, I would expect to see a qualified interrupt() like this:
public void cancel() { Thread.currentThread().interrupt(); }
也就是说中断你自己的线程,而不是线程运行的任务。如果您想让其他事情停止正在做的事情,打断自己是没有意义的:您可以简单地停止正在做的事情。
(您可能会中断当前线程,例如,如果您刚刚捕获了一个 InterruptedException
,并希望保留线程被中断的事实。但您不会将此用作一种机制开始中断)。
The confusing thing is that the book states that Threads should implement an Interruption Policy
对,
class MyThread extends Thread {
@Override
public void interrupt() { ... }
}
while Runnable / Callable tasks should implement a Cancellation Policy.
对,
// FutureTask = Runnable (for run) + Future<Void> (for cancel(boolean))
class MyTask extends FutureTask<Void> {
@Override
public boolean cancel(boolean mayInterruptIfRunning) { ... }
@Override
public void run() { ... }
}
Yet here we are with a cancel() method inside of a Thread object.
Thread
既是Thread
又是Runnable
,所以interrupt
(中断this线程)和cancel
(要取消 this 任务,该线程当前正在 运行 的任务)应该被定义。
public class Thread implements Runnable { ... }
PrimeProducer
示例有点令人困惑,因为它假定 PrimeProducer
中定义的任务将在 PrimeProducer
之外使用。
class PrimeProducer extends Thread {
public void run() {
try {
BigInteger p = BigInteger.ONE;
while (!Thread.currentThread().isInterrupted())
queue.put(p = p.nextProbablePrime());
} catch (InterruptedException consumed) {
/* Allow thread to exit */
}
}
public void cancel() { interrupt(); }
}
非常合理和准确,因为我们可以做到
Runnable runnable = new PrimeProducer();
new Thread(runnable).start();
不过这种情况很少见。我们很可能会选择
new PrimeProducer().start();
这将使我们在 run
中定义的任务具有上下文感知能力,Thread.currentThread().isInterrupted()
和 isInterrupted()
的含义相同。这就是你对 Thread.currentThread().interrupt()
和 interrupt()
的困惑。
在书中,Java Brian Goetz 等人的并发实践,第 141 页的示例 (2006):
7.5: Using interruption for cancellation.
class PrimeProducer extends Thread {
}
...
public void cancel() { interrupt(); }
令人困惑的是,书中指出线程应实施 中断策略,而可运行/可调用任务应实施取消策略.
然而这里我们在 Thread 对象中使用了一个 cancel()
方法。 这是怎么回事?几页之前,用 cancel()
给出了一个带有 Runnable 的例子 (7.1)。对于任务,我希望看到这样的合格 interrupt()
:
public void cancel() { Thread.currentThread().interrupt(); }
额外的、半相关的信息
我正在使用 ExecutorService,所以我处理任务(不是线程——ExecutorService 的线程工厂除外),但我找不到任何可能的 ExecutorService 完全关闭(许多线程)的示例这本书。
我启动和停止任务的方法是:
Map<CancellableRunnable, Future<?>> cancellableFutures = new HashMap<>(); // keep track of refs to tasks for stop()
public void init() {
Future<?> future = myExecutorService.submit(myTask);
cancellableFutures.put(myTask, future);
}
public void stop() {
for (Future task : cancellableFutures.values()) {
task.cancel(true); // also a confusing step. Should it be cancel() on Future or cancel() on task (Runnable/Callable)?
}
}
要正确关闭一个线程,您必须通过调用 thread.interrupt()
要求它自行关闭并且该线程应定期检查 thread.isInterrupted()
方法。
在 official documentation 中查看更多详细信息。
对于您的示例,您有一个 ExecutorService myExecutorService
。要关闭所有提交的线程(以及 线程池 本身),您可以调用 myExecutorService.shutdown()
。结果,线程池为所有线程调用 thread.interrupt()
。
要仅停止所需的线程,请正确调用 future.cancel(true)
。在这种情况下,您的 线程池 将处于活动状态并且能够提交另一个任务。
In the case of tasks, I would expect to see a qualified interrupt() like this:
public void cancel() { Thread.currentThread().interrupt(); }
也就是说中断你自己的线程,而不是线程运行的任务。如果您想让其他事情停止正在做的事情,打断自己是没有意义的:您可以简单地停止正在做的事情。
(您可能会中断当前线程,例如,如果您刚刚捕获了一个 InterruptedException
,并希望保留线程被中断的事实。但您不会将此用作一种机制开始中断)。
The confusing thing is that the book states that Threads should implement an Interruption Policy
对,
class MyThread extends Thread {
@Override
public void interrupt() { ... }
}
while Runnable / Callable tasks should implement a Cancellation Policy.
对,
// FutureTask = Runnable (for run) + Future<Void> (for cancel(boolean))
class MyTask extends FutureTask<Void> {
@Override
public boolean cancel(boolean mayInterruptIfRunning) { ... }
@Override
public void run() { ... }
}
Yet here we are with a cancel() method inside of a Thread object.
Thread
既是Thread
又是Runnable
,所以interrupt
(中断this线程)和cancel
(要取消 this 任务,该线程当前正在 运行 的任务)应该被定义。
public class Thread implements Runnable { ... }
PrimeProducer
示例有点令人困惑,因为它假定 PrimeProducer
中定义的任务将在 PrimeProducer
之外使用。
class PrimeProducer extends Thread {
public void run() {
try {
BigInteger p = BigInteger.ONE;
while (!Thread.currentThread().isInterrupted())
queue.put(p = p.nextProbablePrime());
} catch (InterruptedException consumed) {
/* Allow thread to exit */
}
}
public void cancel() { interrupt(); }
}
非常合理和准确,因为我们可以做到
Runnable runnable = new PrimeProducer();
new Thread(runnable).start();
不过这种情况很少见。我们很可能会选择
new PrimeProducer().start();
这将使我们在 run
中定义的任务具有上下文感知能力,Thread.currentThread().isInterrupted()
和 isInterrupted()
的含义相同。这就是你对 Thread.currentThread().interrupt()
和 interrupt()
的困惑。