这是停止执行任务的正确方法吗?

时间:2011-01-16 18:10:23

标签: java multithreading

我遇到了代码来停止执行任务。

private final ExecutorService executor = Executors.newSingleThreadExecutor();

public void stop() {
    executor.shutdownNow();
    try {
        executor.awaitTermination(100, TimeUnit.DAYS);
    } catch (InterruptedException ex) {
        log.error(null, ex);
    }
}


public Runnable getRunnable() {
    return new Runnable() {
        public void run() {
            while (!Thread.currentThread().isInterrupted()) {
                // What if inside fun(), someone try to clear the interrupt flag?
                // Say, through Thread.interrupted(). We will stuck in this loop
                // forever.
                fun();
            }
        }
    };
}

我意识到,Runnable可能永远循环,如

  1. 未知fun可能Thread.sleep,清除中断标志并忽略InterruptedException
  2. 未知fun可能Thread.interrupted,清除中断标志。

  3. 我在想,是用以下方法修正代码的正确方法吗?

    private final ExecutorService executor = Executors.newSingleThreadExecutor();
    private volatile boolean flag = true;
    
    public void stop() {
        flag = false;
        executor.shutdownNow();
        try {
            executor.awaitTermination(100, TimeUnit.DAYS);
        } catch (InterruptedException ex) {
            log.error(null, ex);
        }
    }
    
    
    public Runnable getRunnable() {
        return new Runnable() {
            public void run() {
                while (flag && !Thread.currentThread().isInterrupted()) {
                    // What if inside fun(), someone try to clear the interrupt flag?
                    // Say, through Thread.interrupted(). We will stuck in this loop
                    // forever.
                    fun();
                }
            }
        };
    }
    

4 个答案:

答案 0 :(得分:4)

无法确保未知功能结束。如果有趣,如下所示,您将无法在不关闭应用程序的情况下终止它。

  void fun(){
     while(true){
        try{
           ...
        }catch(Throwable th){

        }
     }
  } 

为Runnable添加标志不会对此有帮助,因为fun()永远不会退出。有几种方法可以终止像Thread.destroy()那样的Threads,因为它会使程序处于未知状态。

确保函数终止的方法只有两种:

  • 确保它遵循指定的行为。对你而言,这将是:不要永远循环,不要清除被打断的旗帜或你自己的旗帜。
  • 或者,在jvm的单独实例中运行该函数,如果函数没有返回而不终止主程序,则可以终止jvm。

如果您可以控制fun()或者知道它最终将返回,那么添加您自己的标志将是一个有效的解决方案您应该确保它按照您的预期处理中断。

答案 1 :(得分:1)

如果我理解你的问题:

  • fun由第三方提供,您不信任(或者您有理由怀疑它写得不好。)
  • 您无法修改或替换fun
  • 您希望通过不受信任的方法保护您的代码免受(有意或无意)拒绝服务。

这是不可能的。
fun可能无法终止,因为它正在静默清除中断,但是由于无限循环可能无法终止,或者它可能正在做其他有害的事情,例如致电System.exitThread.suspend

如果唯一的问题是静音清除中断(或允许fun正常返回的其他内容),那么您的flag会修复它,但我建议使用executor.isShutDown()代替

答案 2 :(得分:0)

我认为这正是执行者服务的javadoc中记录的内容,不是吗?

答案 3 :(得分:0)

如果您不需要在循环结束后设置标志,则可以使用Thread.interrupted()。如果它是结束循环的唯一方法,那么你的代码应该假设它被中断了(如果你的循环后没有代码,你就不必担心了)

如果您的线程正在运行不受信任的代码,则阻止它的唯一安全方法是在单独的进程中运行它。如果失败你可以打断它,最后停止()它。 stop()有许多不良副作用(请参阅javadoc),但最好让线程继续运行。