【问题标题】:Wait for thread loop to be done等待线程循环完成
【发布时间】:2011-12-09 03:10:09
【问题描述】:

我想创建一个方法来安全地停止在循环中运行的线程,允许最后一个循环在将控制权返回给停止器之前完成。

现在,无论我尝试什么,我都会冻结。可能摆脱僵局或诸如此类; Java 不是我常用的环境,因此为什么这可能是另一个等待/通知问题。

boolean isRunning = true;

@Override
public void run() {
    super.run();

    while (isRunning) {
        // Do work...
    }

    synchronized(this) {
        this.notify();
    }
}

public void stopSafely() {
    isRunning = false;

    try {
        synchronized(this) {
            this.wait();
        }
    } catch (InterruptedException ex) {
        // Handle...
    }
}

这种方法的问题(除了我在this 上进行同步,但这是为了示例简单起见),如果notifywait 之前被调用,调用者将冻结。

我确信在synchronized 中使用我环绕的积​​木可以解决问题,但我似乎无法获得正确的组合。

有什么想法吗?

【问题讨论】:

    标签: java multithreading wait notify


    【解决方案1】:

    选择真正简单的解决方案:

    private volatile boolean isRunning = true;
    
    @Override
    public void run() {
        while (isRunning) {
            // Do work...
        }
    }
    
    public void stopThread() {
        isRunning = false;
    }
    

    这基本上就是 Thread.interrupted() 在内部所做的,所以你也可以使用它:

    @Override
    public void run() {
        while (Thread.interrupted()) {
            // Do work...
        }
    }
    

    在这种情况下,您必须在线程上调用interrupt()

    【讨论】:

      【解决方案2】:

      我希望第二种方法是从另一个线程调用的,而不是使用 run 方法的线程。我敢打赌。

      在这种情况下,将 isRunning=false 放在同步块中就足够了。只有一个线程可以进入在给定监视器上同步的块。

      顺便说一句,不要调用super.run(),它没用,也不是一个好的编程习惯。

      【讨论】:

        【解决方案3】:

        首先要从 make isRunning volatile 开始。

        volatile boolean isRunning = true;
        

        问题是java运行时做了一些优化,即使第一个线程改变了值,值也没有反映在另一个线程中。

        【讨论】:

          【解决方案4】:

          找到了一个更简单的解决方案,它只是阻止在进行更改时检查isRunning

          boolean isRunning = true;
          
          @Override
          public void run() {
              while (true) {
                  synchronized(this) {
                      if (!isRunning) break;
                  }
          
                  // Do work...
              }
          }
          
          public void stopSafely() {
              synchronized(this) {
                  isRunning = false;
              }
          }
          

          【讨论】:

          • 如果你保留这个,使用私有同步 stopSafely() { isRunning=false;} 更简单和等效。
          • 但是像你这样同步整个run方法并不是一个好主意。
          • 正如所写,这将使任何对 stopSafely 的调用陷入僵局,不是吗?
          • 你说得对,我为你的 cmets 改变了方法。请看编辑。
          • 此方法使用同步作为内存屏障。由于您实际上并未使用等待、通知或执行任何需要原子性的操作,因此您应该使用 @Voo 的建议,即仅使用 volatile 变量。
          猜你喜欢
          • 2012-09-30
          • 1970-01-01
          • 2017-05-03
          • 2020-11-10
          • 1970-01-01
          • 1970-01-01
          • 2014-07-19
          • 1970-01-01
          相关资源
          最近更新 更多