Java多线程错误`java.lang.IllegalMonitorStateException`

时间:2016-10-29 08:19:25

标签: java multithreading

我试图让两个线程相互打印出来,但我得到的结果是:

0
Exception in thread "Thread-0" wait in decrement
java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at thread.Multithread2.increment(Multithread2.java:38)
    at thread.Multithread2.run(Multithread2.java:18)
    at java.lang.Thread.run(Unknown Source)

我已经在synchronized块中包含了共享对象,并在此对象上调用了wait()/ notify()。我不知道为什么它仍然会抛出异常。

public class Multithread2 implements Runnable {

    private Integer integer;
    private int method;

    public Multithread2(Integer integer, int method) {
        this.integer = integer;
        this.method = method;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(20);
            for(int i = 0; i < 5; i++) {
                if(method == 1) {
                    increment();
                } else {
                    decrement();
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void increment() throws InterruptedException {
        synchronized(integer) {
            while(integer > 0) {
                integer.wait();
            }
            System.out.println(integer);
            integer++;
            integer.notify();
        }
    }

    public void decrement() throws InterruptedException {
        synchronized(integer) {
            while(integer <= 0) {
                integer.wait();
            }
            System.out.println("decrement: " + integer);
            integer--;
            integer.notify();
        }
    }
}

主要方法:

Integer integer = new Integer(0);
Thread t1 = new Thread(new Multithread2(integer, 1));
t1.start();
Thread t2 = new Thread(new Multithread2(integer, 2));
t2.start();

1 个答案:

答案 0 :(得分:2)

integer++

相当于

integer = Integer.valueOf(integer.getValue() + 1);

因此它使用不同的Integer实例初始化整数变量。整数是不可变的,因此它的状态不能改变。因为你在这个新的Integer实例上调用notify(),并且你没有获得这个新实例的锁定,所以你得到了那个例外。

使用您自己的,可变的,线程安全的Counter类。在共享的,不可变的Integer实例上进行同步是一个糟糕的主意。顺便说一句,一个好的经验法则是制作同步final的字段。这样做会导致编译错误,在这种情况下编译错误是你的朋友,只要你注意实际上对你说的是什么。