illegalMonitorException,同时使用2个不同的线程打印奇数偶数

时间:2017-04-21 17:49:44

标签: java multithreading

以下是我使用2个不同线程打印奇数偶数的代码。 但是在运行代码时,我收到了IllegalMonitorException。

请帮助我理解为什么我会收到这个例外。

class PrintOddEven {

    public static void main(String args[]) {
        Integer num = new Integer(1);
        Thread odd = new Thread(new Odd(num));
        Thread even = new Thread(new Even(num));
        odd.start();
        even.start();
    }
}

class Odd implements Runnable {
    Integer num;

    public Odd(Integer num) {
        super();
        this.num = num;
    }

    @Override
    public void run() {
        while (num <= 100) {
            try {
                synchronized (num) {
                    if (num % 2 == 0) {
                        num.wait();
                    }
                    System.out.println(num);
                    num++;
                    num.notifyAll();
                    num.wait();

                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Even implements Runnable {

    Integer num;

    public Even(Integer num) {
        super();
        this.num = num;
    }

    @Override
    public void run() {
        while (num <= 100) {
            try {
                synchronized (num) {
                    if (num % 2 != 0) {
                        num.wait();
                    }
                    System.out.println(num);
                    num++;
                    num.notifyAll();
                    num.wait();
                }

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

请帮助我理解为什么这段代码会抛出illegalMonitorException

2 个答案:

答案 0 :(得分:0)

    Integer num = new Integer(1);
    System.out.println(num.hashCode());
    num++;
    System.out.println(num.hashCode());

如果你执行这段代码,你会发现hashcode是不同的(这是它们的值,即1和2)所以如果hashcode不同,那么它怎么可能是同一个对象(如指出的那样)出自@Nathan Hughes)。这就是你得到java.lang.IllegalMonitorStateException

的原因
import java.util.concurrent.atomic.AtomicInteger;

class PrintOddEven {

    public static void main(String args[]) {
        AtomicInteger num = new AtomicInteger(1);
        Thread odd = new Thread(new Odd(num));
        Thread even = new Thread(new Even(num));
        odd.start();
        even.start();
    }
}

class Odd implements Runnable {
    AtomicInteger num;

    public Odd(AtomicInteger num) {
        super();
        this.num = num;
    }

    @Override
    public void run() {
        while (num.get() < 100) {
            try {
                synchronized (num) {
                    if (num.get() % 2 == 0) {
                        num.wait();
                    }
                    System.out.println(num);
                    num.getAndIncrement();
                    num.notifyAll();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Even implements Runnable {

    AtomicInteger num;

    public Even(AtomicInteger num) {
        super();
        this.num = num;
    }

    @Override
    public void run() {
        while (num.get() <= 100) {
            try {
                synchronized (num) {
                    if (num.get() % 2 != 0) {
                        num.wait();
                    }
                    System.out.println(num);
                    num.getAndIncrement();
                    num.notifyAll();
                }

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

答案 1 :(得分:0)

整数对象是不可变的。当您更改其值时,您将使用新实例替换变量引用的对象。线程获取num引用的对象上的锁,然后递增该数,从而用另一个替换该对象。然后,线程在num引用的对象上调用notifyAll,这是与获取锁定的对象不同的对象。您不允许这样做,这是IllegalMonitorStateException告诉您的内容。

TLDR:锁定在一个变量上,它不在一个对象上。增加不可变对象的值会将该对象交换为其他任何未获取其锁定的对象。

使用您不能用于其他任何事情的专用锁,并将其传递给您的奇数和偶数对象。