【问题标题】:How to stop and resume thread safely in Java?如何在 Java 中安全地停止和恢复线程?
【发布时间】:2012-08-08 01:04:54
【问题描述】:

我有正在运行的线程,我想停止并稍后在某个时间点恢复。我学会了不使用 stop() 等,因为这些已被弃用,并且在下面的代码中似乎成功地停止了线程。它只是退出运行方法。现在,我该如何重新启动它?如果我调用 start() 方法,它表示线程仍在运行,那么在这种情况下直接调用 run() 会做吗?它会引起任何问题吗?顺便说一句,这适用于 Android 应用程序,如果这有什么不同的话。

private volatile stopThread;

public void stopButton() {
    // this is called when button is clicked
    // and thread is already started and running
    stopThread= true;
}

public void run() {

    while (!stopThread) {
        // do something here
    }

    stopThread=false;
}

编辑:它是一个在线程启动时启动的计时器,然后可以暂停并再次启动。所以 timer 是一个包含 Thread 对象的类(我已经用 SurfaceView 扩展了这个类)。

【问题讨论】:

  • 你能详细说明你想恢复线程的条件吗?
  • 你不能在同一个线程上调用start 两次。线程是否保持需要重用的状态,或者您可以启动一个全新的线程?
  • 您需要wait()notify() 方法。请参阅this 了解一些重要细节。
  • 顺便说一句,改变你思考问题的方式有很大帮助。您不想停止和恢复线程。你想阻止一些特定的工作完成,然后再继续做这项工作。这种思考问题的转变将引导您进行更明智的实施。专注于线程正在做的工作,为什么你不想做那个工作,以及如何明智地反映欲望的变化。 (为什么线程编码来做你不想做的工作?)

标签: java multithreading thread-safety


【解决方案1】:

安全地停止和恢复线程的唯一安全方法是在线程主体的相关点添加代码来处理它。 (不要使用已弃用的线程停止/暂停/恢复,因为它们根本不安全。)

停止而不恢复相对简单,使用特定于应用程序的标志或Thread.interrupt() 机制。后者可能更好,因为 Java 的一些同步和 IO API 可以感知中断。但是,您确实遇到了很多现有库无法感知中断,或者没有正确处理 InterruptedException 的问题。

停止并恢复更棘手。您需要创建自己的类,如下所示:

public class PauseControl {
    private boolean needToPause;

    public synchronized void pausePoint() {
        while (needToPause) {
            wait();
        }
    }

    public synchronized void pause() {
        needToPause = true;
    }

    public synchronized void unpause() {
        needToPause = false;
        this.notifyAll();
    }
}

并在整个线程代码的相关点添加对myPauseControl.pausePoint() 的调用。请注意,这将不允许您暂停 IO 或“子”线程中的活动,并且它只会在您调用 pausePoint 方法的代码中的点处暂停。此外,您还需要注意在线程锁定其他对象或其他对象等待响应时暂停线程会造成问题。

【讨论】:

  • 顺便说一句:java.io 不知道中断。然而,java.nio 是。
【解决方案2】:

Java 1.4 文档解释了原因,并通过使用 wait()notify() 替代了各种已弃用的 Thread 方法,包括 suspend()resume()

在页面的中间寻找标题What should I use instead of Thread.suspend and Thread.resume?

【讨论】:

    【解决方案3】:

    Thread 类的 stop() 方法已被弃用且使用不安全,因为停止 Thread 会导致它解锁所有已锁定的监视器。这会产生破坏性后果,因为任何处于不一致状态的对象(以前受监视器保护)现在都可能被处于不一致状态的其他线程查看。这种行为可能很微妙且难以检测。

    你永远不会直接调用 run() 方法,如果你使用 volatile 变量方法停止线程,线程就会终止。为了启动线程,再次执行 new Thread().start()。

    【讨论】:

      猜你喜欢
      • 2011-05-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-22
      • 1970-01-01
      • 2010-11-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多