我们都知道为了调用Object.wait(),这个调用必须放在同步块中,否则抛出IllegalMonitorStateException。但是为什么要做出这样的限制呢?我知道wait()释放监视器,但为什么我们需要通过使特定块同步显式获取监视器,然后通过调用wait()释放监视器?

如果可以在同步块之外调用wait(),保留它的语义——挂起调用者线程,那么潜在的损害是什么?


当前回答

我们都知道wait(), notify()和notifyAll()方法用于线程间 通信。为摆脱误信号和伪唤醒问题,等待线程 总是等待一些条件。 例如,

boolean wasNotified = false;
while(!wasNotified) {
    wait();
}

然后通知线程集wasNotified变量为true和notify。

每个线程都有自己的本地缓存,所以所有的更改都先写在那里 然后逐步提升到主存。

是否这些方法没有在同步块中调用,wasNotified变量 不会被刷新到主内存中,而是在线程的本地缓存中 因此,等待线程将继续等待信号,尽管它已通过通知重置 线程。

为了修复这些类型的问题,这些方法总是在同步块中调用 这确保当同步块开始时,那么一切将从主读取 内存,并将在退出同步块之前被刷新到主内存。

synchronized(monitor) {
    boolean wasNotified = false;
    while(!wasNotified) {
        wait();
    }
}

谢谢,希望它能澄清。

其他回答

根据文档:

当前线程必须拥有该对象的监视器。线程释放 这个监视器的所有权。

Wait()方法仅仅意味着它释放对象上的锁。因此,对象只在同步块/方法中被锁定。如果线程在同步块之外意味着它没有被锁定,如果它没有被锁定那么你会释放对象上的什么?

我们都知道wait(), notify()和notifyAll()方法用于线程间 通信。为摆脱误信号和伪唤醒问题,等待线程 总是等待一些条件。 例如,

boolean wasNotified = false;
while(!wasNotified) {
    wait();
}

然后通知线程集wasNotified变量为true和notify。

每个线程都有自己的本地缓存,所以所有的更改都先写在那里 然后逐步提升到主存。

是否这些方法没有在同步块中调用,wasNotified变量 不会被刷新到主内存中,而是在线程的本地缓存中 因此,等待线程将继续等待信号,尽管它已通过通知重置 线程。

为了修复这些类型的问题,这些方法总是在同步块中调用 这确保当同步块开始时,那么一切将从主读取 内存,并将在退出同步块之前被刷新到主内存。

synchronized(monitor) {
    boolean wasNotified = false;
    while(!wasNotified) {
        wait();
    }
}

谢谢,希望它能澄清。

如果在wait()之前没有同步,可能会导致如下问题:

If the 1st thread goes into makeChangeOnX() and checks the while condition, and it is true (x.metCondition() returns false, means x.condition is false) so it will get inside it. Then just before the wait() method, another thread goes to setConditionToTrue() and sets the x.condition to true and notifyAll(). Then only after that, the 1st thread will enter his wait() method (not affected by the notifyAll() that happened few moments before). In this case, the 1st thread will stay waiting for another thread to perform setConditionToTrue(), but that might not happen again.

但是如果你把synchronized放在改变对象状态的方法之前,这就不会发生。

class A {

    private Object X;

    makeChangeOnX(){
        while (! x.getCondition()){
            wait();
            }
        // Do the change
    }

    setConditionToTrue(){
        x.condition = true; 
        notifyAll();

    }
    setConditionToFalse(){
        x.condition = false;
        notifyAll();
    }
    bool getCondition(){
        return x.condition;
    }
}

直接从这个Java oracle教程:

当线程调用d.wait时,它必须拥有d -的内在锁 否则抛出错误。在synchronized中调用等待 方法是一种获取内在锁的简单方法。

当您在对象t上调用notify()时,Java会通知特定的t.wait()方法。但是,Java如何搜索并通知特定的等待方法呢?

Java只查看被对象t锁定的同步代码块。Java不能搜索整个代码来通知特定的t.wait()。