IllegalMonitorStateException 尽管从同步上下文调用 notifyAll()

IllegalMonitorStateException despite calling notifyAll() from synchronised context

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();
        }
    }
}

错误是

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() 并从正确的对象调用它。

您正在从线程下更改锁定。每次将布尔值设置为某个东西时,它就是一个不同的对象;代码

            mutex=true;
            mutex.notifyAll();

将 mutex 设置为与线程同步的对象不同的对象(因此线程尚未为其获取监视器),然后在新对象上调用 notifyAll。

使用单锁,不要更改。

锁定布尔值、数字包装器或字符串太容易出错,应该避免。不仅您最终会遇到您所看到的错误,而且应用程序的其他不相关部分(可能是由其他人按照相同的做法编写的)可能锁定在同一个对象上并导致神秘的问题。布尔值、数字包装器和字符串可用于 JVM 中的所有内容。最好使用范围受限的锁,这样您的应用程序中的其他任何东西都无法获取它。

通常最好使用专用锁,不要将其用于任何其他目的。超载不同用途的东西很容易造成麻烦。

如果有人需要,请更正代码

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();
        }
    }

}
}