为什么wait/notify/notifyAll方法在java中不同步?
在Java中,每当我们需要调用wait/notify/notifyAll时,我们都需要访问对象监视器(通过同步方法或通过同步块)。所以我的问题是,为什么java不支持同步的wait/notify方法,从而消除了从同步块或方法调用这些方法的限制为什么wait/notify/notifyAll方法在java中不同步?,java,multithreading,synchronization,synchronized,Java,Multithreading,Synchronization,Synchronized,在Java中,每当我们需要调用wait/notify/notifyAll时,我们都需要访问对象监视器(通过同步方法或通过同步块)。所以我的问题是,为什么java不支持同步的wait/notify方法,从而消除了从同步块或方法调用这些方法的限制 如果这些被声明为已同步,它将自动进行监视器访问 有更多多线程经验的人可以随意介入,但我相信这会消除同步块的多功能性。使用它们的目的是在作为监视资源/信号量的特定对象上进行同步。然后使用wait/notify方法控制同步块内的执行流 请注意,synchron
如果这些被声明为已同步,它将自动进行监视器访问 有更多多线程经验的人可以随意介入,但我相信这会消除同步块的多功能性。使用它们的目的是在作为监视资源/信号量的特定对象上进行同步。然后使用wait/notify方法控制同步块内的执行流
请注意,synchronized方法是在方法(或静态方法的类)期间在此上同步的缩写。同步wait/notify方法本身将删除它们作为线程之间的停止/前进信号的使用点。好问题。我认为,报告中的评论对这一点有所启发(我的重点): 此方法导致当前线程(称为
T
)放置
自身处于等待集,等待该对象,然后放弃任何
以及此对象上的所有同步声明
然后将线程T
从该线程的等待集中删除
以常规方式与其他线程进行同步,以便在
对象一旦获得对对象的控制,其所有
对象上的同步声明将恢复为现状
ante-即,到<代码>等待<代码>
方法已被调用线程T
然后从
调用等待
方法。因此,在从
wait
方法,对象和线程的同步状态
T
与使用wait
方法时完全相同
调用
因此,我认为需要注意的第一点是,wait()。这意味着,如果wait()
本身是同步的,那么调用方将继续持有对象上的锁,其他人将无法wait()
或notify()
现在很明显,wait()
在幕后做了一些棘手的事情,以迫使调用方无论如何都失去对对象的锁的所有权,但是如果wait()
本身被同步,这个技巧可能不会起作用(或者更难发挥作用)
第二点是,如果多个线程正在等待一个对象,当使用notify()
来唤醒其中一个线程时,标准争用方法将只允许一个线程在该对象上同步,并且wait()
应该将调用者的同步声明恢复到调用wait()
之前的确切状态。在我看来,要求调用方在调用wait()
之前持有锁可能会简化这一过程,因为这样就不需要检查调用方在wait()
返回后是否应该继续持有锁。契约规定调用方必须继续持有锁,因此简化了一些实现
或者,这样做只是为了避免出现逻辑悖论:“如果wait()
和notify()
都是同步的,并且wait()
在调用notify()
之前不会返回,那么这两种方法如何才能成功使用?”
无论如何,这些都是我的想法。对于notify和notifyAll,您的想法的问题在于,当您通知时,您通常会在同一个同步块中执行其他操作。因此,使notify方法同步不会给您带来任何好处,您仍然需要块。同样,wait必须在同步块或方法中才能有用,例如在自旋锁中,测试无论如何都必须同步。因此,锁定的粒度与您的建议完全不符
下面是一个示例,这是关于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();
}
}
}
公共类MyQueue{
私有列表=新的ArrayList();
public T take()抛出InterruptedException{
已同步(列表){
while(list.size()==0){
list.wait();
}
返回列表。删除(0);
}
}
公开作废认沽权(T对象){
已同步(列表){
列表。添加(对象);
list.notify();
}
}
}
因此,您可以让生产者线程向队列中添加内容,消费者线程将内容取出。当一个线程要从队列中取出一些东西时,它需要在同步块中检查列表中是否有东西,并且在收到通知后,它需要重新获取锁并确保列表中仍然有东西(因为其他消费线程可能已经介入并抓取了它)。还有“虚假唤醒”现象:你不能依赖被唤醒作为发生事情的充分证据,你需要检查你等待的任何条件是否真实,这需要在同步块内完成
在这两种情况下,都需要在锁定的情况下对等待进行检查,这样当代码根据这些检查采取操作时,它就会知道这些结果当前有效。我猜需要同步
块的原因是使用等待()
或通知()
作为同步中的唯一操作
synchronized(lock)
update condition
lock.notify()
synchronized(lock)
while( condition not met)
lock.wait()
// producer
give(element){
list.add(element)
lock.notify()
}
// consumer
take(){
obj = null;
while(obj == null)
lock.wait()
obj = list.remove(0) // ignore error indexoutofrange
return obj
}
// consumer
take(){
while(list.isEmpty()) // 1
lock.wait()
return list.remove(0) // 2
}
// producer
give(element){
list.add(element)
lock.notify()
}
rollback(element){
list.remove(element)
}
// business code
produce(element){
try{
give(element)
}catch(Exception e){
rollback(element) // or happen in another thread
}
}
// consumer
take(){
obj = null;
while(obj == null)
lock.wait()
obj = list.remove(0) // ignore error indexoutofrange
return obj
}