了解Future的可中断取消

时间:2016-05-15 11:19:15

标签: java multithreading

Java Concurrency In Practice声明如下:

  

线程只能由其所有者中断;主人可以   将线程中断策略的知识封装在一个   适当的取消机制,如关机方法

现在让我们来看看标准FutureTask实施:

public boolean cancel(boolean mayInterruptIfRunning){

    //...
    if (mayInterruptIfRunning) {
       try {
            Thread t = runner;
            if (t != null)
               t.interrupt(); //Future task may not be an owner, 
                              //yet it interrupts the running thread.
        }
    //...
    }
    //...
}

那么,为什么它安全?如果ThreadPoolExecutornewTaskFor实现为

protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
    return new FutureTask<T>(runnable, value);
}

这样打电话是否安全:

ExecutorService es;
Callable<Integer> task;
//init es, task
Future<Integer> ft = es.submit(task);
ft.cancel(true); //Attention at this line, thread may be interrupted

如果是ThreadPoolExecutor,我们不知道线程中断策略,FutureTask也不知道。然而,我们通过FutureTask打断它。这有点令人困惑......

3 个答案:

答案 0 :(得分:1)

没有人声称它安全&#34;。措辞是&#34;线程应该仅由其所有者&#34;中断,而不是必须

如果您正在调用cancel(true),那么您应该为中断线程可能产生的任何影响做好准备。

答案 1 :(得分:1)

本书的引用是作者对最佳实践的意见,而不是关于线程安全的声明。不幸的是,这本书没有明确区分这两种陈述。

答案 2 :(得分:1)

首先,让我们确保问题是合法的。从书中引用:

  

因为每个线程都有自己的中断策略,所以除非您知道中断对该线程的意义,否则不应该中断线程。

FutureTask是否中断底层线程由mayInterruptIfRunning参数控制。因此FutureTask没有决定何时中断线程,调用者决定。并且调用者应该知道什么是中断策略,因为她控制执行服务。

另一方面,ThreadPoolExecutor并未真正记录中断其主题的合同(cancels tasks via Thread#interruptshutdownNow()除外),因此违反了原则来电者。

我认为ThreadPoolExecutor合同可以在这方面得到改善。但它的行为很自然。使用中断标志是如何让执行任务知道取消的最简单方法(否则可以将可查询状态的对象传递给任务,这将是繁琐的。)

  

那么,为什么安全?

在这种情况下,ThreadPoolExecutor并不关心我们是否中断线程。只有在里面运行的任务可能会关心,而且这些任务都在调用者的控制之下。 ThreadPoolExecutor确保的唯一两件事是在新任务启动之前清除中断标志,并且在关闭时线程被中断(这不违反原则,因为执行者拥有线程)。