Java 尽管从同步上下文调用notifyAll(),但仍存在IllegalMonitorStateException
错误是Java 尽管从同步上下文调用notifyAll(),但仍存在IllegalMonitorStateException,java,multithreading,synchronized,Java,Multithreading,Synchronized,错误是 public class Alternate { static Boolean mutex = true; public static void main(String[] args) { Thread t1 = new Thread(new Odd(mutex)); Thread t2 = new Thread(new Even(mutex)); t1.start(); t2.start(); }
public class Alternate {
static Boolean mutex = true;
public static void main(String[] args) {
Thread t1 = new Thread(new Odd(mutex));
Thread t2 = new Thread(new Even(mutex));
t1.start();
t2.start();
}
}
class Odd implements Runnable{
Boolean mutex;
Odd( Boolean mutex){
this.mutex=mutex;
}
@Override
public void run() {
try {
synchronized(mutex){
while(mutex){
mutex.wait();
}
System.out.println("odd");
mutex=true;
mutex.notifyAll();
Thread.sleep(500);
}
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Even implements Runnable{
Boolean mutex;
Even( Boolean mutex){
this.mutex=mutex;
}
@Override
public void run() {
try {
synchronized(mutex){
while(!mutex){
mutex.wait();
}
System.out.println("even");
mutex=false;
mutex.notifyAll();
Thread.sleep(500);
}
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
我无法找出错误的原因。我正在从同步上下文调用notifyAll(),并从正确的对象调用它。您正在更改线程下的锁定。每次将布尔值设置为某个值时,这是一个不同的对象;代码
java.lang.IllegalMonitorStateException
at java.lang.Object.notifyAll(Native Method)
at com.test.concurrency.Even.run(Alternate.java:55)
at java.lang.Thread.run(Thread.java:722)
将互斥体设置为与线程同步的对象不同的对象(因此线程尚未为其获取监视器),然后在新对象上调用notifyAll
使用单个锁,不要更改它
锁定布尔、数字包装或字符串太容易出错,应该避免。您不仅会看到错误,而且应用程序的其他不相关部分(可能是由其他人按照相同的实践编写的)可能会锁定同一个对象并导致神秘的问题。Boolean、数字包装器和字符串可用于JVM中的所有内容。最好使用范围受限的锁,这样应用程序中的其他任何东西都无法获取它
通常情况下,最好使用专用锁,而不是用于任何其他目的。过载不同用途的东西太容易引起麻烦 如果有人需要,请更正代码
mutex=true;
mutex.notifyAll();
导入java.util.concurrent.AtomicInteger;
公务舱候补{
静态最终AtomicInteger互斥=新的AtomicInteger(0);
公共静态void main(字符串[]args){
线程t1=新线程(新的奇数());
螺纹t2=新螺纹(新偶数());
t1.start();
t2.start();
}
静态类奇数实现可运行{
@凌驾
公开募捐{
试一试{
因为(inti=0;iBoolean是不可变的。)这样一个愚蠢的错误:-(。谢谢lot@Renjith:yw,这是一个很容易犯的错误。@Renjith。这与Boolean
是否不可变无关-在调用notifyAll
之前,您正在更改对完全不同对象的引用-这才是最重要的。(我想补充Nathan的回答,在任何现实世界的程序中,使用诸如Boolean
之类的包装类型作为互斥是一个非常糟糕的主意)。如果它是可变的,我可以在不更改对象的情况下单独修改值。无论如何,使用任何包装器作为互斥对象确实是一个非常糟糕的主意。Thanks@James:我认为Renjith的意思是他可以使用某种容器,在这种容器中,他可以更改内容,而不必交换包含对象,这是可行的对不同对象的引用和不变性或易变性是无关的。
import java.util.concurrent.atomic.AtomicInteger;
public class Alternate {
static final AtomicInteger mutex = new AtomicInteger(0);
public static void main(String[] args) {
Thread t1 = new Thread(new Odd());
Thread t2 = new Thread(new Even());
t1.start();
t2.start();
}
static class Odd implements Runnable{
@Override
public void run() {
try {
for(int i=0;i<10;i++){
synchronized(mutex){
while(mutex.get()==1){
mutex.wait();
}
System.out.println("odd");
mutex.compareAndSet(0, 1);
mutex.notifyAll();
}
}
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class Even implements Runnable{
@Override
public void run() {
try {
for(int i=0;i<10;i++){
synchronized(mutex){
while(mutex.get()==0){
mutex.wait();
}
System.out.println("even");
mutex.compareAndSet(1, 0);
mutex.notifyAll();
}
}
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}