为什么Boolean flag也不能用作wait()/ notifyAll()mutex?

时间:2015-03-25 11:29:36

标签: java multithreading

我有一个长期运行的Runnable。它在run()函数中的while循环内执行大量迭代。我需要暂停和恢复runnable的功能,我使用可以由另一个线程设置的volatile pauseFlag实现。

Runnable检测到pauseFlagtrue后,会调用pauseFlag.wait()暂停执行。通过将pauseFlag设置为false然后调用pauseFlag.notifyAll()来完成恢复。

所以pauseFlag都充当了旗帜和互斥体。但是,这种组合功能不起作用。 Runnable无限期地阻止pauseFlag.wait()

如果我创建一个单独的互斥锁,比如Object mutex = new Object();并使用mutex.notifyAll() / mutex.wait(),同时仍然使用pauseFlag作为布尔标志,则Runnable 会执行按预期行事。

非工作代码如下所示:

public class PausableRunnable implements Runnable
{
    private boolean done;

    private volatile Boolean pauseFlag = false;

    /** Pause execution. This is an asynchronous (non-blocking) call. */
    public void pause() // <-- called by another thread
    {
        pauseFlag = true;
    }

    /** Resume execution */
    public void resume() // <-- called by another thread
    {
        pauseFlag = false;
        synchronized (pauseFlag)
        {
            pauseFlag.notifyAll();
        }
    }

    @Override
    public void run()
    {
        try
        {
            while (!done && !Thread.currentThread().isInterrupted())
            {
                while (pauseFlag)
                {
                    synchronized (pauseFlag)
                    {
                        // Pause flag was set. Suspend until we are notified that we can continue
                        pauseFlag.wait();
                    }
                }
                // execute our main behaviour. set done = true when done iterating.
                // ....
            }
        } catch (InterruptedException e)
        {
            Thread.currentThread().interrupt();
        }
    }
}

所以,虽然我通过使用单独的对象找到了解决方案,但我想了解这个问题。为什么上述实现不起作用?

1 个答案:

答案 0 :(得分:8)

我曾犯过同样的错误。

wait / notify适用于对象,而非引用

更改

引用的对象时

private volatile Boolean pauseFlag

wait仍然指的是原始对象。 (正如评论中指出的那样,通常只有两个布尔对象,TRUEFALSE,这使得调试更加困难,因为你可能偶然得到正确的一个)

因此,在使用wait / notify时,最好使用永远不会更改其基础对象的final引用。