为什么线程t1会出现illegalmonitorstateexception

doinxwow  于 2021-08-20  发布在  Java
关注(0)|答案(1)|浏览(392)

我得到下面代码的这个错误

First thread about to sleep
thread 1  run
Boolean assignment done.
Woke up and about to invoke wait()
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Object.java:502)
    at IncorrectSynchronization$1.run(HelloWorld.java:23)
    at java.lang.Thread.run(Thread.java:748)

当线程t1处于休眠状态时,我将另一个线程的锁修改为false。然后抛出这个非法的MonitorStateException。它仍然是同一个对象,为什么修改值会导致illegalmonitorstateexception?
当我从同步块中的另一个线程将锁修改为false时,我不再得到该错误。有人能解释引擎盖下发生的事情的原因吗?

public class HelloWorld{

   public static void main( String args[] ) throws InterruptedException {
        SampleTest.runExample();
    }
}

class SampleTest{

    Boolean flag = new Boolean(true);

    public void example() throws InterruptedException {

        Thread t0 = new Thread(new Runnable() {

            public void run() {
                synchronized (flag) {
                    try {
                        while (flag) {
                            System.out.println("First thread about to sleep");
                            Thread.sleep(2000);
                            System.out.println("Woke up and about to invoke wait()");
                            flag.wait();
                            System.out.println("wait() called");

                        }
                    } catch (InterruptedException ie) {

                    }
                }
            }
        });

        Thread t1 = new Thread(new Runnable() {

            public void run() {
                System.out.println("thread 1  run");
                flag = false;
              }
        });

        t0.start();
        Thread.sleep(200);
        t1.start();
        t0.join();
        t1.join();
    }

    public static void runExample() throws InterruptedException {
        SampleTest test = new SampleTest();
        test.example();
    }
}
rqqzpn5f

rqqzpn5f1#

这一行的问题在于:

flag = false;

这将更改 flag 布尔变量,来自原始 Boolean 对象(它是由不推荐使用的构造函数创建的,不应使用该构造函数)添加到预创建的 Boolean.FALSE 示例(由于自动装箱)。当第一个线程调用 flag.wait() ,对象不再与用于同步的对象相同,因此 IllegalMonitorStateException .
在这种情况下,最好使用 AtomicBoolean 并在另一个线程中改变其值:

AtomicBoolean flag = new AtomicBoolean(true);

现在,第二个线程可以更新同一对象的值。它还可能通知等待对象的第一个线程(如 wait() , notify() 还需要在调用它的对象上进行同步):

Thread t1 = new Thread(new Runnable() {

     public void run() {
         synchronized(flag) {
             System.out.println("thread 1  run");
             flag.set(false);
             flag.notify();
         }
       }
 });

相关问题