简体   繁体   中英

Why is my code throwing an IllegalMonitorStateException?

I am trying to understand how threads work in Java. Hence I wrote a small piece of code where by I create two threads, one printing all odd numbers and other printing even numbers, and trying to synchronize between them so that all the numbers are printed in order.

public class Main 
{

    public static void main (String args[]){

        Main lock = new Main();

        Test t1 = new Test(1, lock);

        Test t2 = new Test(2, lock);

        synchronized(lock){

            (new Thread(t1)).start();
            (new Thread(t2)).start();

        }


    }

}

public class Test implements Runnable {


    int n;
    Main lock;

    public Test(int newN, Main lockObj){
        this.n = newN;
        this.lock = lockObj;
    }


    public void run() {


        while(true){

            if (n != 1){
                try {
                    lock.wait();
                } catch (InterruptedException e) {

                    e.printStackTrace();
                }
            }

            n = n + 2;

            System.out.println(n);

            lock.notify();

        }


    }


}

Can someone please help understand what the underlying problem is?

You have three threads, the main thread, t1 and t2 . The thread owning the lock can use actions notify , notifyAll and wait . In this case the main thread owns the lock not t1 or t2 .

You will need to synchronize within the run method of each thread to be able to wait .


Here is an example of what I mean by synchronizing in the run method.

Any operation that happens from the run method after you start the thread will be done by that thread running. So when you try and wait you will want to make sure the thread owns the lock, you can do this by synchronizing it in the run method.

public void run() {
     synchronized(lock){
         while(true){
            if (n != 1){
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
               }
            }
            n = n + 2;
            System.out.println(n);
            lock.notify();
        }
    }
}

As you can see I am synchronizing within the run method so that t1 and t2 own the locks while notifying or waiting.

This will probably not help you understanding the low-level threading mechanics, but for your case it would make sense to use a CyclicBarrier with a barrierAction.

Make both treads wait on the barrier after processing n = n + 2 , let the barrierAction sysout both thread's current n , repeat.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM