【问题标题】:IllegalMonitorStateException despite calling notifyAll() from synchronised contextIllegalMonitorStateException 尽管从同步上下文调用 notifyAll()
【发布时间】:2015-07-29 17:57:32
【问题描述】:
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() 并从正确的对象调用它。

【问题讨论】:

    标签: java multithreading synchronized


    【解决方案1】:

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

                mutex=true;
                mutex.notifyAll();
    

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

    使用单个锁并且不要更改它。

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

    通常最好使用专用锁,您不会将其用于任何其他目的。重载具有不同用途的东西很容易引起麻烦。

    【讨论】:

    • 布尔值是不可变的..真是个愚蠢的错误:-(。非常感谢
    • @Renjith:是的,这是一个容易犯的错误。
    • @Renjith。它与Boolean 是否不可变无关——在调用notifyAll 之前,您正在更改对完全不同对象的引用——这才是最重要的。 (我想补充一下 Nathan 的回答,在任何现实世界的程序中,使用包装器类型(如 Boolean)作为互斥锁都是一个非常糟糕的主意)。
    • 如果它是可变的,我可以单独修改值而不改变对象。无论如何,使用任何包装器作为互斥锁确实是一个非常糟糕的主意。谢谢
    • @James:我认为 Renjith 的意思是他可以使用某种容器来更改内容,而无需换出包含对象,这将起作用。但是是的,当使用 = 更改对不同对象的引用时,不变性或可变性无关紧要。
    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-01
      • 2013-08-15
      • 2020-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-11
      • 1970-01-01
      相关资源
      最近更新 更多