【问题标题】:Getting illegal monitor state exception on notify在通知时获取非法监视器状态异常
【发布时间】:2015-12-23 12:22:32
【问题描述】:

下面的程序应该通过两个不同的线程打印偶数和奇数,但是我在下面的代码中的 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)

【问题讨论】:

标签: java multithreading


【解决方案1】:

Java 包装器中的整数是不可变的,因此一旦您执行t++,您将分配一个您没有锁定的新整数对象,因此您会得到IllegalMonitorStateException

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

【讨论】:

  • 对于整数对象 t++ 等价于 t = Integer.valueOf(t.intValue() + 1);
【解决方案2】:

问题在于使用整数对象进行同步,而不是对其进行增量(++)操作。我认为它创建了新的整数对象,而不是所有的同步逻辑都在折腾。我不确定,因为在调试代码时,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
            }
        }

    }

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-13
    • 2016-02-12
    相关资源
    最近更新 更多