简体   繁体   English

Java并发实践中的“使用中断取消”中是否有错字

[英]Is there a typo in "Using interruption for cancellation" in Java Concurrency in Practice

In the book, Java Concurrency in Practice by Brian Goetz et al, the example on page 141 (2006):在 Brian Goetz 等人的 Java Concurrency in Practice 一书中,第 141 页(2006 年)中的示例:

7.5: Using interruption for cancellation. 7.5:使用中断取消。

class PrimeProducer extends Thread {
}
...
public void cancel() { interrupt(); }

The confusing thing is that the book states that Threads should implement an Interruption Policy , while Runnable / Callable tasks should implement a Cancellation Policy .令人困惑的是,书中指出线程应该实现中断策略,而 Runnable/Callable 任务应该实现取消策略

Yet here we are with a cancel() method inside of a Thread object.然而这里我们在 Thread 对象中使用了一个cancel()方法。 What's up with that?那是怎么回事? A few pages before, an example with Runnable is given (7.1) with cancel() .几页之前,给出了一个带有 Runnable 的示例 (7.1) 和cancel() In the case of tasks, I would expect to see a qualified interrupt() like this:在任务的情况下,我希望看到一个合格的interrupt()像这样:

public void cancel() { Thread.currentThread().interrupt(); }

Extra, semi-relevant information额外的、半相关的信息

I am using an ExecutorService, so I deal with tasks (not threads--except for a thread factory for the ExecutorService), but I could not find any could examples of a full ExecutorService shutdown (of many threads) in the book.我正在使用 ExecutorService,所以我处理任务(不是线程——除了 ExecutorService 的线程工厂),但我在书中找不到任何完整的 ExecutorService 关闭(许多线程)的示例。

My methods for starting tasks and stopping them are:我启动和停止任务的方法是:

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)?
  }
}

In the case of tasks, I would expect to see a qualified interrupt() like this:在任务的情况下,我希望看到一个合格的 interrupt() 像这样:

 public void cancel() { Thread.currentThread().interrupt(); }

That interrupts your own thread, not the thread running the task.这会中断您自己的线程,而不是运行任务的线程。 There's no point in interrupting yourself if you want something else to stop what it's doing: you can simply stop what you're doing instead.如果你想让其他事情阻止它正在做的事情,那么打断自己是没有意义的:你可以简单地停止你正在做的事情。

(You might interrupt the current thread, for example, if you have just caught an InterruptedException , and want to preserve the fact that the thread was interrupted. But you don't use this as a mechanism to start the interruption). (您可能会中断当前线程,例如,如果您刚刚捕获了一个InterruptedException ,并且想要保留线程被中断的事实。但是您不使用它作为启动中断的机制)。

The confusing thing is that the book states that Threads should implement an Interruption Policy令人困惑的是,这本书指出线程应该实现中断策略

Right,对,

class MyThread extends Thread {
    @Override
    public void interrupt() { ... }
}

while Runnable / Callable tasks should implement a Cancellation Policy.而 Runnable / Callable 任务应该实现取消策略。

Right,对,

// 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 对象中使用了一个 cancel() 方法。

Thread is both Thread and Runnable , so both interrupt (to interrupt this thread) and cancel (to cancel this task, the task currently being run by this thread) should be defined. Thread既是Thread又是Runnable ,所以interrupt (中断这个线程)和cancel (取消这个任务,这个线程当前正在运行的任务)都应该定义。

public class Thread implements Runnable { ... }

The PrimeProducer example is a bit confusing because it assumes the task defined in PrimeProducer will be used outside PrimeProducer . PrimeProducer示例有点令人困惑,因为它假定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(); }

}

It's very reasonable and accurate since we can do这是非常合理和准确的,因为我们可以做到

Runnable runnable = new PrimeProducer();
new Thread(runnable).start();

It's rarely the case, though.不过,这种情况很少见。 It's highly likely we would simply go with我们很可能只会选择

new PrimeProducer().start();

which would make the task we define in run context-aware and Thread.currentThread().isInterrupted() and isInterrupted() would mean the same.这将使我们在run上下文感知中定义的任务和Thread.currentThread().isInterrupted()isInterrupted()意味着相同。 That's what your confusion over Thread.currentThread().interrupt() and interrupt() comes from.这就是你对Thread.currentThread().interrupt()interrupt()困惑的来源。

To correctly close a thread, you have to ask it to close itself by calling thread.interrupt() and the thread should periodically check thread.isInterrupted() method.要正确关闭线程,您必须通过调用thread.interrupt()要求它关闭自己,并且该线程应定期检查thread.isInterrupted()方法。

See more details in official documentation .官方文档中查看更多详细信息。

For your example, you have an ExecutorService myExecutorService .对于您的示例,您有一个ExecutorService myExecutorService To close all submitted threads (along with thread pool itself), you could call myExecutorService.shutdown() .要关闭所有提交的线程(以及线程池本身),您可以调用myExecutorService.shutdown() As a result, the thread pool calls thread.interrupt() for all threads.结果,线程池为所有线程调用thread.interrupt()

To stop required threads only, you do correct calling future.cancel(true) .要仅停止所需的线程,请正确调用future.cancel(true) In this case, your thread pool will be alive and will able to submit another task.在这种情况下,您的线程池将处于活动状态并且能够提交另一个任务。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM