“This is the 15th day of my participation in the First Challenge 2022. For details: First Challenge 2022.”

In multithreaded programming, wait allows the current thread to sleep until notify or notifyAll is called by another thread. In Java, wait and notify/notifyAll have their own format requirements, that is, wait and notify (notifyAll is similar to notify, Synchronized must be used with notify. Synchronized is synchronized.

Wait /notify Basic use

The basic methods of wait and notify are as follows:

Object lock = new Object();
new Thread(() -> {
    synchronized (lock) {
        try {
            System.out.println("Wait until");
            // Call the wait method
            lock.wait();
            System.out.println(After the "wait");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}).start();

Thread.sleep(100);
synchronized (lock) {
    System.out.println("Executive notify");
    // Call notify
    lock.notify();
}
Copy the code

The execution result of the above code is shown below:

Wait /notify and synchronized?

“Wait” and “notify” are always used with synchronized. Can wait and notify be used separately? We tried to delete the synchronized code line in the above code, and the implementation code is as follows:At first glance, the code appears to be fine, and the compiler reports no errors, as if it were “working”. However, when we run the above program, we get the following error:As can be seen from the above results:Both wait and notify, if not cooperate with synchronized use together, the program is running will be submitted to the IllegalMonitorStateException illegal monitor abnormal state, and notify also cannot achieve the function of program awakens.

Cause analysis,

From the error message above we can see that the JVM at runtime check wait and notify mandatory for the synchronized code, if not will be submitted to the illegal monitor abnormal state (IllegalMonitorStateException), But this is just the programming surface of the runtime, so why is Java designed this way? In fact, the reason for this design is to prevent multi-threaded concurrent running, the execution of the program chaos. At first glance, this sentence seems to be used to describe “lock”. In practice, however, wait and Notify introduce locks to avoid clutches in concurrent execution. So what exactly is this “execution chaos problem”? So let’s move on.

Wait and notify problems reoccur

Assuming that wait and notify can be unlocked, we use them to implement a custom blocking queue. The blocking queue here refers to the read operation blocking, that is, when reading data, if there is data to return data, if there is no data to block waiting data, the implementation code is as follows:

class MyBlockingQueue {
    // A collection of data to store
    Queue<String> queue = new LinkedList<>();

    /** * add method */
    public void put(String data) {
        // Add data to queue
        queue.add(data); 
        // Wake up the thread to continue execution (thread here refers to the thread executing the take method)
        notify(); / / 3.
    }

    /** * get method (block execution) * return data if there is data in the queue, block waiting for data if there is no data *@return* /
    public String take(a) throws InterruptedException {
        // Use while to determine if there is data (use while instead of if to prevent false wake up)
        while (queue.isEmpty()) { / / 1.
            // No task, block and wait
            wait(); / / 2.
        }
        return queue.remove(); // Return data}}Copy the code

Notice the above code, in which we identified three key execution steps: ① Determine whether there is data in the queue; ② : Execute wait hibernation. ③ Add data to the queue and wake up the blocking thread. If synchronized is not mandatory, the following problems occur:

steps Thread 1 Thread 2
1 Perform step 1 check whether there is no data in the queue
2 Perform step 3 to add data to the queue and wake up thread 1 to continue
3 Go to step 2. Thread 1 is hibernated

Do you see any problems with the above execution flow? If wait and notify do not enforce locking, another thread adds data to the queue after thread 1 has made a judgment, but before sleeping. However, thread 1 has already made the decision, so it goes to sleep, permanently leaving the queue unreadable. This is the problem of “execution chaos” when the program is running concurrently. When used with synchronized, however, the code looks like this:

class MyBlockingQueue {
    // To save a collection of tasks
    Queue<String> queue = new LinkedList<>();

    /** * add method */
    public void put(String data) {
        synchronized (MyBlockingQueue.class) {
            // Add data to queue
            queue.add(data);
            // To prevent the take method from blocking sleep, call notify
            notify(); / / 3.}}/** * get method (block execution) * return data if there is data in the queue, block waiting for data if there is no data *@return* /
    public String take(a) throws InterruptedException {
        synchronized (MyBlockingQueue.class) {
            // Use while to determine if there is data (use while instead of if to prevent false wake up)
            while (queue.isEmpty()) {  / / 1.
                // No task, block and wait
                wait(); / / 2.}}return queue.remove(); // Return data}}Copy the code

After the thread executes step ③, thread 1 can read the data in the queue. Their execution flow is as follows:

steps Thread 1 Thread 2
1 Perform step 1 check that no data exists in the queue
2 Step 2 The thread enters the hibernation state
3 Perform Step 3 to add data to the queue and wake up the queue
4 The thread wakes up and resumes execution
5 Determine that there is data in the queue and return data

This allows our programs to execute normally, which is why Java designs must use Wait and Notify alongside synchronized.

conclusion

This article introduces the basic uses of WAIT and notify, and why wait and notify/notifyAll must be used in conjunction with synchronized. If wait and notify/notifyAll are not enforced together with synchronized, the problem with multi-threaded execution is that the wait is half-executed, followed by the addition of data and notify, causing the thread to sleep forever.

Judge right and wrong from yourself, praise to listen to others, gain and loss in the number.

Public number: Java interview analysis

Interview collection: gitee.com/mydb/interv…