如何使用wait()和notify()正确暂停线程

4

我希望有一个类,可以启动一个线程,并提供暂停和继续该线程的方法。我的第一种尝试是使用标志,只要值为true,就循环执行sleep方法。代码如下:

public class Bot {
private Thread t ;
private boolean isPaused;

public Bot(){
    t = new Thread(new Runnable(){
        @Override
        public void run() {
            while (true) {
                System.out.println("Hi");


                while(isPaused){
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    });

    t.start();
}
public void pauseBot(){
    isPaused = true;
}

public void continueBot(){
    isPaused = false;
}
}

但是,由于线程仍在运行并浪费CPU,我认为这不是一个好的解决方案。如果使用wait()和notify()会怎么样呢?我看了各种关于这个主题的教程,但是我无法将它们应用到我的问题上。
每次我尝试时,要么出现IllegalMonitorStateException,要么代码停止整个应用程序,而不仅仅是我想停止的线程。
我还有另一个问题:如何防止线程在关键时刻被暂停,例如...
Runnable r = new Runnable(){

    @Override
    public void run() {
        while(true){
            task1();
            task2();

            //Thread mustn't be stopped from here....
            task3();
            task4();
            task5();
            task6();
            task7();
            //... to here

            task8();
            task9();
            task10();
        }

    }

};

因为当 task3() 到 task7() 处理一些在线程暂停时会过期的内容时,必须有一种方式让线程完成 task7() 直到它暂停。

希望你能帮我解决这个问题。 先感谢您, Flo


可能是如何安全地停止和恢复Java线程?的重复问题。 - Anshul
1个回答

4

因此,假设这是您的Thread类:

public class MyThread extends Thread
{

首先,您需要一个锁对象。这个对象可以是任何东西,如果使用现有对象,则占用的内存较少。还要定义一个标志,指示机器人是否应该暂停。

    public Object lock = this;
    public boolean pause = false;

现在,为线程定义一个pause()continue()方法。这会设置pause标志。
    public void pause ()
    {
        pause = true;
    }

    public void continue ()
    {
        pause = false;

在这里,您需要唤醒线程。请注意锁对象上的同步,以避免出现IllegalMonitorStateException异常。

        synchronized (lock)
        {
            lock.notifyAll();
        }
    }

不要定义一个需要手动暂停线程的方法。你可以在每个线程可以被暂停的时刻自动调用该方法。
    private void pauseThread ()
    {
        synchronized (lock)
        {
            if (pause)
                lock.wait(); // Note that this can cause an InterruptedException
        }
    }

现在,您可以在run()方法中定义线程:
    public void run ()
    {
        task1();
        task2();

        pauseThread();

        task3();
        task4();
        task5();
        task6();
        task7();

        pauseThread();

        task8();
        task9();
        task10();
    }
}

1
“this can be everything” 是什么意思? - Solomon Slow
@jameslarge 这可以是任何对象,只要线程调用wait()notify()方法。 - msrd0
对我来说,这也很奇怪。我不明白为什么你要创建一个仅用于同步的新对象。难道不能直接使用“this”吗? 抱歉,但我认为我需要一些关于同步对象的背景信息。 顺便说一句,谢谢你的回答。 - flxh
@user3187049,就像我之前说的,你可以使用任何东西,所以这没问题,只需要注意在线程中将其作为锁对象使用即可。 - msrd0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接