停止,中断,暂停和恢复java线程

时间:2014-05-21 23:12:19

标签: java multithreading resume suspend

我开始阅读有关如何安全地停止,中断,暂停和恢复java线程的内容,我在oracle文档中找到了以下解决方案:

1-如何安全地停止线程:

private volatile Thread blinker;

public void stop() {
    blinker = null;
}

public void run() {
    Thread thisThread = Thread.currentThread();
    while (blinker == thisThread) {
        try {
            Thread.sleep(interval);
        } catch (InterruptedException e){
        }
        repaint();
    }
}

- 要停止线程我可以使用boolean变量而不是volatile Thread,但为什么Oracle坚持要对启动的线程影响null?在这样做的背后是否有任何秘密(例如使用终结器分配的解放资源)?

2-如何中断等待很长时间的线程:

public void stop() {
    Thread moribund = waiter;
    waiter = null;
    moribund.interrupt();
}

- 我为什么要创建新变量moribund而不是直接使用waiter.interrupt()

3-如何暂停和恢复帖子:

private volatile boolean threadSuspended;

public void run() {
    while (true) {
        try {
            Thread.sleep(interval);

            if (threadSuspended) {
                synchronized(this) {
                    while (threadSuspended)
                        wait();
                }
            }
        } catch (InterruptedException e){
        }
        repaint();
    }
}

public synchronized void mousePressed(MouseEvent e) {
    e.consume();

    threadSuspended = !threadSuspended;

    if (!threadSuspended)
        notify();
}

- 为什么在run方法内添加了循环while (threadSuspended),因为我不明白添加循环的目的是什么,我的代码可以编译,没有它正确运行(具有相同的输出结果)。

来源链接http://docs.oracle.com/javase/8/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html

1 个答案:

答案 0 :(得分:3)

<强> 1 使用本地Thread变量可防止其他线程在您的对象上调用run()方法。只有此对象实例表示的线程才能使用run()方法。通常从不同的run()手动调用Thread Thread方法通常是不好的做法,但肯定是可能的。

<强> 2 这一点需要在第1点的上下文中解释。这部分还考虑了interval非常长的情况,并且线程需要尽快停止。
您当然需要使引用无效,否则第1部分中的代码将继续循环。但请考虑如果将stop方法简化为:

,可能会发生什么
public void stop() {
    waiter.interrupt();
    waiter = null;    
}

由于这是从另一个线程执行的,因此它可以以任何方式与run()方法交织在一起。例如,threadA调用stop()来停止run()中的threadB:

  1. threadB:sleep(interval)
  2. threadA:waiter.interrupt()
  3. threadB:捕获InterruptedException
  4. threadB:调用重绘
  5. threadB:循环时输入下一步
  6. threadB:进入睡眠(间隔)
  7. threadA:waiter == null
  8. 在这种情况下,threadB不会立即停止,而是执行另一个休眠循环,这会使stop a thread that waits for long periods的设置任务失败。在给定的实现中,您首先使null,然后中断,这会阻止这种行为。

    第3 简而言之:因为另一个线程可能已经通知了您的代码,而没有设置正确的标志。 notify()的一般合同是呼叫是无害的(但是无用的呼叫显然会消耗一些资源)。所有线程都应该能够应对虚假的唤醒。