首页 > 解决方案 > IllegalMonitorStateException when use .class as monitor while "this" not

问题描述

I just wrote a program to print 0-99 using two threads by turns. I use synchronized block to finish the job. In my code, when I use "this" as synchronized monitor, the program works well. But when I use ".class" as synchronized monitor, I got IllegalMonitorStateException. Can anyone tell what happened?

Here's my code which works well

public class WaitTest implements Runnable {
    private int n = 0;

    @Override
    public void run() {
        while (true) {
            synchronized (this){
                notify();
                if (n < 100) {

                    System.out.println(Thread.currentThread().getName() + " " + Integer.toString(n));
                    ++n;
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                } else
                    break;
            }
        }
    }

    public static void main(String[] args) {
        WaitTest waitTest = new WaitTest();
        Thread threadA = new Thread(waitTest);
        Thread threadB = new Thread(waitTest);
        threadA.start();
        threadB.start();
    }
}

Here's my code which I got an Exception

public class WaitTest implements Runnable {
    private int n = 0;

    @Override
    public void run() {
        while (true) {
            synchronized (WaitTest.class){
                notify();
                if (n < 100) {

                    System.out.println(Thread.currentThread().getName() + " " + Integer.toString(n));
                    ++n;
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                } else
                    break;
            }
        }
    }

    public static void main(String[] args) {
        WaitTest waitTest = new WaitTest();
        Thread threadA = new Thread(waitTest);
        Thread threadB = new Thread(waitTest);
        threadA.start();
        threadB.start();
    }
}

The only difference between them is the content in the brace after synchronized

标签: javamultithreadingparallel-processingthread-safety

解决方案


In my code, when I use "this" as synchronized monitor, the program works well.

That is because when you call the methods wait() and notify() you are implicitly calling them from the instance return by this, which matches the object used in the your synchronized clause (i.e., synchronized (this)).

But when I use ".class" as synchronized monitor, I got IllegalMonitorStateException.

This happens because you synchronized on the WaitTest.class class but you call the wait and notify methods again for the this instance. Therefore, to avoid that exception change the calls of wait(); and notify(); to WaitTest.class.wait(); and WaitTest.class.notify();, respectively.

The code fixed:

public class WaitTest implements Runnable {
    private int n = 0;

    @Override
    public void run() {
        while (true) {
            synchronized (WaitTest.class){
                WaitTest.class.notify();
                if (n < 100) {

                    System.out.println(Thread.currentThread().getName() + " " + Integer.toString(n));
                    ++n;
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    try {
                        WaitTest.class.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                } else
                    break;
            }
        }
    }

    public static void main(String[] args) {
        WaitTest waitTest = new WaitTest();
        Thread threadA = new Thread(waitTest);
        Thread threadB = new Thread(waitTest);
        threadA.start();
        threadB.start();
    }
}

推荐阅读