Java 在哪里调用wait()

Java 在哪里调用wait(),java,multithreading,Java,Multithreading,在我的java程序中,当我编写代码时 synchronized(a){ a = 55; a.wait(); } 它在a.wait()上给出运行时异常java.lang.IllegalMonitorStateException语句。但是a=55运行成功 但如果我编码为 synchronized(a){ a.wait(); a = 55; } 然后,它毫无例外地完美运行。为什么会这样?因为a在重新分配后指向不同的对象,并且没有在上同步 换句话说,有两个对象,val

在我的java程序中,当我编写代码时

synchronized(a){
    a = 55;
    a.wait();
}
它在
a.wait()上给出运行时异常
java.lang.IllegalMonitorStateException
语句。但是
a=55
运行成功

但如果我编码为

synchronized(a){
    a.wait();
    a = 55;
}

然后,它毫无例外地完美运行。为什么会这样?

因为
a
在重新分配后指向不同的对象,并且没有在上同步

换句话说,有两个对象,
val1
val2
都被分配给变量
a
。在
val1
上进行同步,但在第一个示例中,调用wait on
val2
。您使用的监视器附着到对象,而不是其变量

因此,应该通过引用非最终变量来避免同步。这会导致你的困惑。如果字段是可变的,请使用另一个锁,例如:

Object aMonitor = new Object();

synchronized(aMonitor) {
   a = 55;
   aMonitor.wait();
}

理想情况下,您的场景只是为了学习
wait()
notify()
是原语,除非作为练习或用于构建自己的并发库,否则不应使用它们。如果是针对真实代码,请在中使用更高级别的机制。

,因为
a
在重新分配后指向不同的对象,并且未在上同步

换句话说,有两个对象,
val1
val2
都被分配给变量
a
。在
val1
上进行同步,但在第一个示例中,调用wait on
val2
。您使用的监视器附着到对象,而不是其变量

因此,应该通过引用非最终变量来避免同步。这会导致你的困惑。如果字段是可变的,请使用另一个锁,例如:

Object aMonitor = new Object();

synchronized(aMonitor) {
   a = 55;
   aMonitor.wait();
}

理想情况下,您的场景只是为了学习
wait()
notify()
是原语,除非作为练习或用于构建自己的并发库,否则不应使用它们。如果是真实代码,请在中使用更高级别的机制。

,因为您在执行分配时已替换对象
a
。这就是所谓的自动装箱
a=55
实际上创建了一个新的
Integer
对象,因此当您对其调用
a.wait()
时,它正在等待您尚未同步的另一个对象,这就是为什么会出现异常

正如我在对的回答中提到的,您不能在
synchronized
块内指定对象。即使下面的模式也是一个坏主意,因为当您将
a
分配给不同的对象时,这意味着调用
synchronized
的下一个线程将在不同的
a
上执行,因此两个线程可以同时在同一
synchronized
块中

synchronized(a){
    a.wait();
    // still a bad idea
    a = 55;
}

因为您在执行分配时已替换对象
a
。这就是所谓的自动装箱
a=55
实际上创建了一个新的
Integer
对象,因此当您对其调用
a.wait()
时,它正在等待您尚未同步的另一个对象,这就是为什么会出现异常

正如我在对的回答中提到的,您不能在
synchronized
块内指定对象。即使下面的模式也是一个坏主意,因为当您将
a
分配给不同的对象时,这意味着调用
synchronized
的下一个线程将在不同的
a
上执行,因此两个线程可以同时在同一
synchronized
块中

synchronized(a){
    a.wait();
    // still a bad idea
    a = 55;
}

在第一种情况下,变量a(分配给新整数后)不是已同步(a)锁定的“a”,因此调用.wait()会导致异常。

在第一种情况下,变量a(分配给新整数后)不是已同步(a)锁定的“a”,因此调用.wait()会导致异常