【问题标题】:Java Thread Class : java.lang.IllegalMonitorStateExceptionJava 线程类:java.lang.IllegalMonitorStateException
【发布时间】:2018-03-07 22:50:28
【问题描述】:

这是我的第一篇文章,如果我做错了什么,请见谅。 我试图了解 Java 中的线程是如何工作的,特别是同步,这就是为什么我创建了一小段代码,它应该打印 1、2、3、4、5、6(在一个线程中)然后第二个线程等待第一个完成,然后打印 6,5,4,3,2,1 但它只执行前 6 个步骤并告诉我线程 t2 中的等待方法存在监视器问题和问题通知所有线程 t1。也许我对对象的同步一无所知。这是我的代码:

public class anObject extends Thread {

long value;
String name;

public anObject(long value, String name) {
    this.value = value;
    this.name = name;
}

public synchronized void add() {
    this.value++;
}

public synchronized void sub() {
    this.value--;
}

public static void main(String[] args) {

    anObject il = new anObject(0, "Bob");

    synchronized (il) {

        Thread t1 = new Thread(il) {
            public void run() {
                while (il.value > 0) {
                    try {
                        this.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                for (int i = 0; i < 6; i++) {
                    il.add();
                    System.out.println(il.value);
                    try {
                        sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                il.notifyAll();
            }
        };

        Thread t2 = new Thread(il) {
            public void run() {
                while (il.value < 6) {
                    try {
                        this.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                for (int j = 0; j < 6; j++) {
                    il.sub();
                    System.out.println(il.value);
                    try {
                        sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                il.notifyAll();
            }
        };

        t1.start();
        t2.start();

    }
}

}

这就是终端中出现的内容:

Exception in thread "Thread-2" 1
java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Unknown Source)
at anObject$2.run(anObject.java:53)
2
3
4
5
6
Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
at java.lang.Object.notifyAll(Native Method)
at anObject$1.run(anObject.java:45)

非常感谢您的帮助! 问候

【问题讨论】:

    标签: java multithreading synchronization wait notify


    【解决方案1】:

    wait 是在 Object 中定义的,这就是你得到这个异常的原因。

    我更喜欢专用的以避免不可预知的监视器异常:

    private final Object lock = new Object();
    
    
    private static final class Lock { }
    private final Object lock = new Lock();
    

    对于 notify 或 notifyAll 对象,您需要使用同步语句持有锁。此外,您应该定义一个循环来检查唤醒条件。

    synchronized (lock) {
        while (!isWakeupNeeded()) {
            lock.wait();
        }
    }
    

    通知:

    synchronized (lock) {
        makeWakeupNeeded();
        lock.notifyAll();
    }
    

    【讨论】:

    • 所以你建议我创建一个名为 lock 的 Object 实例并在我的线程中同步它而不是同步 this Object ?
    【解决方案2】:

    你在做什么

    synchronized (il)
    

    只是从主线程中获取对象的监视器。但是在内部,您正在初始化两个新线程并尝试从这两个最近初始化然后启动的线程的上下文中调用 wait() 方法。 IllegalMonitorStateException 的主要思想是,您试图调用一个使用对象锁定上下文的方法,而没有事先获取该对象的锁定。快速修复它的方法就是改变

    while (il.value > 0) {
                    try {
                        this.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
    

    while (il.value > 0) {
                    try {
                        synchronized(this) {
                            this.wait();
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
    

    并在第二个代码块中进行相同的更改。但要真正做到正确,我建议您参考一些描述多线程概念的强大的资源。我想 Oracle 的基本 java 教程会很好。

    【讨论】:

    • 好的,谢谢!我会看看教程。