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

tja*_*ing 4 java multithreading

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

一旦可运行已检测到pauseFlagIS true,它要求pauseFlag.wait()暂停其执行.通过设置然后调用pauseFlag来完成恢复.falsepauseFlag.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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

art*_*tol 8

我曾犯过同样的错误.

wait/ notify适用于对象,而不是引用

当您更改引用的对象时

private volatile Boolean pauseFlag

wait仍参照原来的对象.(正如评论中指出的那样,通常只有两个布尔对象,TRUE并且FALSE这使得调试更难,因为你可能偶然得到正确的一个)

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

  • +1.奇怪的是,从`boolean`到`Boolean`的自动装箱行为使用`Boolean.valueOf()`,它将始终返回对'Boolean.TRUE`或`Boolean.FALSE`的引用,因此您最终会同步并等待在'Boolean.TRUE`或`Boolean.FALSE`上,取决于值.(当然,除非你在某处使用`new Boolean()`.) (2认同)