Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么wait/notify/notifyAll方法在java中不同步?_Java_Multithreading_Synchronization_Synchronized - Fatal编程技术网

为什么wait/notify/notifyAll方法在java中不同步?

为什么wait/notify/notifyAll方法在java中不同步?,java,multithreading,synchronization,synchronized,Java,Multithreading,Synchronization,Synchronized,在Java中,每当我们需要调用wait/notify/notifyAll时,我们都需要访问对象监视器(通过同步方法或通过同步块)。所以我的问题是,为什么java不支持同步的wait/notify方法,从而消除了从同步块或方法调用这些方法的限制 如果这些被声明为已同步,它将自动进行监视器访问 有更多多线程经验的人可以随意介入,但我相信这会消除同步块的多功能性。使用它们的目的是在作为监视资源/信号量的特定对象上进行同步。然后使用wait/notify方法控制同步块内的执行流 请注意,synchron

在Java中,每当我们需要调用wait/notify/notifyAll时,我们都需要访问对象监视器(通过同步方法或通过同步块)。所以我的问题是,为什么java不支持同步的wait/notify方法,从而消除了从同步块或方法调用这些方法的限制


如果这些被声明为已同步,它将自动进行监视器访问

有更多多线程经验的人可以随意介入,但我相信这会消除同步块的多功能性。使用它们的目的是在作为监视资源/信号量的特定对象上进行同步。然后使用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
}