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

}
}