为什么等待/通知/通知所有方法在 java 中不同步?

在 Java 中,当我们需要调用 wait/notify/notifyAll 时,我们需要访问对象监视器(通过同步方法或同步块).所以我的问题是为什么 java 不使用同步等待/通知方法来消除从同步块或方法中调用这些方法的限制.

in Java whenever we need to call wait/notify/notifyAll, we need to have access to object monitor (either through synchronized method or through synchronized block). So my question is why java didn't go for synchronized wait/notify methods removing the restriction of calling these methods from synchronized block or methods.

如果这些被声明为同步,它将自动获取监视器访问权限.

In case these are declared as synchronized, it would have automatically taken the monitor access.

推荐答案

对于 notify 和 notifyAll,您的想法的问题是,当您通知时,您通常在同一个同步块中还有其他事情.因此,使通知方法同步不会给您带来任何好处,您仍然需要该块.同样,等待必须在同步块或方法中才能有用,例如在自旋锁中,无论如何测试都必须同步.因此,对于您的建议,锁定的粒度都是错误的.

For notify and notifyAll, the problem with your idea is that when you notify you also have other stuff you're typically doing in the same synchronized block. So making the notify method synchronized wouldn't buy you anything, you'd still need the block. Likewise wait has to be in a synchronized block or method in order to be useful, such as being inside a spinlock where the test has to be synchronized anyway. So the granularity of locking is all wrong for what you suggest.

这是一个示例,这是关于 Java 中最简单的队列实现:

Here's an example, this is about the simplest queue implementation you can have in Java:

public class MyQueue<T> {

    private List<T> list = new ArrayList<T>();

    public T take() throws InterruptedException {
        synchronized(list) {
            while (list.size() == 0) {
                list.wait();
            }
            return list.remove(0);
        }
    }

    public void put(T object) {
        synchronized(list) {
            list.add(object);
            list.notify();
        }
    }
}

因此,您可以拥有将内容添加到队列的生产者线程和取出内容的消费者线程.当一个线程从队列中取出某些东西时,它需要在同步块中检查列表中是否存在某些东西,一旦收到通知,它需要重新获取锁并确保列表中仍然存在某些东西(因为一些其他消费者线程可能已经介入并抓住了它).还有虚假唤醒"现象:您不能依靠被唤醒作为发生某事的充分证据,您需要检查您正在等待的任何条件for 实际上是正确的,这需要在同步块中完成.

So you can have producer threads that add things to the queue and consumer threads that take things out. When a thread goes to get something out of the queue it needs to check within the synchronized block that there's something in the list, and once it's been notified it needs to reacquire the lock and make sure there is still something in the list (because some other consumer thread could have stepped in and grabbed it).There's also the "spurious wake-up" phenomenon: you can't rely on getting woken up as sufficient evidence that something happened, you need to check that whatever condition you're waiting for is actually true, and that needs to be done within the synchronized block.

在这两种情况下,围绕等待的检查都需要在持有锁的情况下进行,这样当代码根据这些检查采取行动时,它就知道这些结果当前是有效的.

In both of these cases, checks surrounding the wait need to be made with the lock held so that when the code takes action based on those checks it knows that those results are currently valid.

相关文章