在通知上获取非法监视器状态异常

时间:2015-12-23 12:22:32

标签: java multithreading

以下程序应该通过两个不同的线程打印偶数和奇数但我在下面的代码中的notify方法上得到非法的监视器异常:

public class oddeven {
    static volatile Integer t = 0;

    public static void main(String as[]) {
        oddrunnable or = new oddrunnable(t);
        evenrunnable er = new evenrunnable(t);

        Thread t1 = new Thread(or, "odd");
        Thread t2 = new Thread(er, "even");

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

    }

}

class oddrunnable implements Runnable {
    Integer t;

    public oddrunnable(Integer t) {
        this.t = t;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub

        synchronized (t) {
            while (true) {

                if (t % 2 == 0) {
                    try {
                        t.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                System.out.println("Current thread id " + Thread.currentThread().getName());
                t++;
                t.notify();
            }
        }
    }

}

class evenrunnable implements Runnable {
    Integer t;

    public evenrunnable(Integer t) {
        this.t = t;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub

        // TODO Auto-generated method stub

        synchronized (t) {
            while (true) {

                if (t % 2 != 0) {
                    try {
                        t.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                System.out.println("Current thread id " + Thread.currentThread().getName());
                t++;
                t.notify(); // <-------------------exception on this line
            }
        }

    }

}

在同步对象本身上调用notify方法。不知道为什么会这样:

    Current thread id even
Exception in thread "even" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at evenrunnable.run(oddeven.java:86)
    at java.lang.Thread.run(Thread.java:619)

2 个答案:

答案 0 :(得分:6)

java包装器中的整数是不可变的,所以只要你执行t++,就会分配一个你没有锁定的新的Integer对象,因此你得到IllegalMonitorStateException。< / p>

使用AtomicInteger代替整数,然后使用incrementAndGet api来增加计数器的值。

答案 1 :(得分:1)

问题在于使用Integer对象进行同步,而不是对其执行增量(++)操作。我认为它创建新的整数对象而不是所有同步逻辑都是为了折腾。我不确定它在调试你的代码时,eclipse没有显示它是否创建了新对象。

更好的选择是在整数或AtomicInteger类周围使用一些包装器对象。以下是使用AtomicInteger类的代码

public class oddeven {
    static volatile AtomicInteger t = new AtomicInteger(0);

    public static void main(String as[]) {
        oddrunnable or = new oddrunnable(t);
        evenrunnable er = new evenrunnable(t);

        Thread t1 = new Thread(or, "odd");
        Thread t2 = new Thread(er, "even");

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

    }

}

class oddrunnable implements Runnable {
    AtomicInteger t;

    public oddrunnable(AtomicInteger t) {
        this.t = t;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub

        synchronized (t) {
            while (true) {

                if (t.intValue() % 2 == 0) {
                    try {
                        t.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                System.out.println("Current thread id " + Thread.currentThread().getName());
                t.incrementAndGet();
                t.notify();
            }
        }
    }

}

class evenrunnable implements Runnable {
    AtomicInteger t;

    public evenrunnable(AtomicInteger t) {
        this.t = t;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub

        // TODO Auto-generated method stub

        synchronized (t) {
            while (true) {

                if (t.intValue() % 2 != 0) {
                    try {
                        t.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                System.out.println("Current thread id " + Thread.currentThread().getName());
                t.incrementAndGet();

                t.notify(); // <-------------------exception on this line
            }
        }

    }

}
相关问题