Interesting talk on IllegalMonitorStateException -- the usage of notify()/notifyAll() and wait()

Posted by cmp241 on Mon, 27 Dec 2021 15:29:00 +0100

Most of them are generated in the use of wait() and notify()?

The reason for the error is: synchronized(A) and B.wait(),A and B should be the same object.

If you search this and report an error, I think your foundation should not be very good. So keep looking.

So this article talks about how to correctly use notify()/notifyAll() and wait(). It's certainly right to understand the principle and modify your code.

First, make clear the following conclusions: (I know no one likes to read theories, so I can skip and look directly at the little girl's story below)

1.synchronized(A) can lock object A, that is, get the object lock (monitor lock) of object A, and the object lock of object A is owned by only one thread at any time.

What is an object lock? The simple understanding is that each object has a lock. This lock can only be occupied by one thread at the same time. Which thread gets it is who gets it. It's very much like monogamy. As for the re-entry lock, it's a bit off the topic.

This article will use the synchronized method to obtain the object Lock (monitor Lock), and of course, the Lock method can obtain the monitor Lock, which will not be discussed for the time being.

2. Both notify() / notifyall() and wait() need to interact through objects, similar to A.wait(). It must also be used in synchronized protected synchronization code.

Specifically, why interact through objects? I've looked for a lot of information, but I still don't understand it. I think that's how the java author designed it, leaving such a set of methods in the Object class for the interaction between threads. It is far fetched to force an explanation (leaders are also welcome to leave a message to talk about their understanding).

So why do these methods need to be protected by synchronized code blocks? Because object locks can only be obtained through synchronized.

3. The thread calling the wait() method will release the object lock. (at this time, the thread becomes a disk receiving thread, which can be seen more clearly in combination with point 4)

4. The thread calling notify()/notifyAll() method will notify the disk receiving threads (note "we", because more than one thread may be wait ing(), which is also the use of notifyAll()): you (we) have a chance to accept the disk!

Attention! There is a chance! Why? Because the thread calling the notify() method (the owner of the monitor at this time) has not released the object lock.

When to release the object lock?

After the synchronized method block, of course.

Let's make a demo. It's difficult to read other people's code, so I used the Chinese programming you like, hee hee.

The plot of the story is as follows:

1. Girl LOCK_ The girl dates three boys at the same time.

2. Later, the girl threw herself into the arms of Gao Fu and handsome

3. The girl was ruthlessly abandoned by Gao fushuai and went to get back together with three boys.

import lombok.SneakyThrows;
public class Test {

    //The girl swam between three losers and a tall, rich and handsome man
    private static final Object LOCK_girl = new Object();

    public static void main(String[] args) throws InterruptedException {
        //First of all, the girl had a relationship with three boys
        new Thread(new Boy(),"Pan Xia 1").start();
        new Thread(new Boy(),"Pan Xia 2").start();
        new Thread(new Boy(),"Pan Xia 3").start();
        //In order to let the three disc takers have enough time to date girl once and sleep for a while
        Thread.sleep(100);
        //The girl ran to Gao Fu Shuai
        new Thread(new tall, rich and handsome(),"tall, rich and handsome").start();
    }

    static class Boy implements Runnable {

        @SneakyThrows
        @Override
        public void run() {
            synchronized (LOCK_girl) {
                System.out.println(Thread.currentThread().getName()
                        +"--I asked the girl for the first time, but the girl suddenly disappeared");
                //Release constant Lock, the thread status changes from running to waiting, and the thread enters the waiting queue
                LOCK_girl.wait();
                System.out.println(Thread.currentThread().getName()
                        +"--The girl came back and took the dish successfully!");
            }
        }
    }


    /**
     * Thread for notify
     */
    static class tall, rich and handsome implements Runnable {

        @SneakyThrows
        @Override
        public void run() {

            synchronized (LOCK_girl){
                System.out.println("I am:"+Thread.currentThread().getName());
                Thread.sleep(3000);

                //Pay attention to usage. It's not Gao Fu's handsome thread to inform the disk receiver. Otherwise, does anyone want to take the disk? In reality, there may be...
                //The girl chose two catchers: I'm free.
                LOCK_girl.notify();
                LOCK_girl.notify();
                System.out.println("The girl informed the receiver");
                //Note that only after the synchronized method block is completed can the disk takers have the opportunity to take the disk!
                Thread.sleep(1000);
                System.out.println(
                    Thread.currentThread().getName()+"Has abandoned the girl");
            }
        }
    }

}

Print it out like this:

 

This result should be noted as follows:

1. Even if the girl notify()/notifyAll() in Gaofu Shuai thread, the boys still have no chance to have the girl's object lock.

Because notify()/notifyAll() only moves boys from WaitQueue (queue in wait state, which can be understood as spare tire pool) to synchronized queue (because girls' object locks can only be owned by one thread at the same time, boys are in this queue at this time, which can be understood as employment pool).

It must be after the Synchronized method block of Gaofu Shuai thread ends that the boys have the opportunity to compete for the girl's object lock.

You see, how hard it is for a boy to catch up with a girl... I had to struggle in two spare wheel pools to get a chance.

2. The code is not over at this time, because the girl only notifies () two boys, and another boy is waiting!

3.WaitQueue and synchronized queue seem to be queues. In fact, their choices are random, not in the order of first in first out. This is stated in the jdk comment (I'm not sure it's right).

As for the order problem, it may not be so easy to understand the experiment with notify(). Replace it with notifyAll(). The results are as follows:

You can see that the order in which three boys have girl object locks is disordered compared with the order in which they have girl object locks.

This also shows that Synchronized is an unfair lock, and it does not guarantee that threads are first come, first served.

Of course, Synchronized is also a reentrant lock. This chapter will not discuss it temporarily. Readers can make up the picture by themselves. It is not suitable for children.

 

Topics: Java Multithreading Concurrent Programming thread