Java multi-threading series III (wait+notify+notifyAll)

1. First introduction to wait, notify, notifyAll

We know that due to the preemptive execution of threads, the scheduling between threads is random and disordered. But in some scenarios we need to reasonably coordinate the execution order of multiple threads. We know that using join can control the order of thread execution, but joinit can only allow one thread to finish executing and then execute another thread, and the function is limited. Therefore, we introduced a set of APIs such as waitand notify/notifyAllto more flexibly control the order of thread execution.

for example:

For the above situation, we can use to wait/notifyeffectively solve it:

If Zhang San finds that the ATM has no money, he (wait) releases the lock and walks out of the ATM machine, and blocks and waits (temporarily not participating in CPU scheduling and lock competition) until someone deposits money into the ATM machine. When the time is right, he You can wake up (notify) Zhang San and continue to participate in the ATM lock competition.

2. Introduction to wait, notify, notifyAll functions

1、wait()

wait(): If you find that the conditions are not met/the time is not mature, call wait() to block and wait, and release the current lock at the same time. When certain conditions are met, you can be awakened and try to acquire the lock again.

Note : Using wait() to block and wait will cause the thread to enter the WAITING state.

wait wait end condition:

  1. Other threads call the object's notify method.
  2. wait wait timeout (wait method provides a version with timeout parameter to specify the waiting time).
  3. Other threads call the interrupted method of the waiting thread, causing wait to throw an InterruptedException exception.

2、notify()

notify(): When other threads construct a mature condition, they can call notify() to wake it up.

Notes on notify:

  1. The method notify() must also be called in a synchronized method or synchronized block. This method is used to notify other threads that may be waiting for the object lock of the object, notify them, and enable them to reacquire the object lock of the object.
  2. If there are multiple threads waiting, the thread scheduler randomly selects a thread in the wait state. (There is no "first come, first served")
  3. After the notify() method, the current thread will not release the object lock immediately. The object lock will not be released until the thread executing the notify() method finishes executing the program, that is, after exiting the synchronized code block.

3、notifyAll()

notifyAll(): notify() just wakes up a waiting thread. Use notifyAll() to wake up all threads waiting for the same object at once.

notifyAll Notes:

Although multiple threads are awakened at the same time, these multiple threads need to compete for locks, so they are not executed at the same time, but the one that acquires the lock first is still executed first.

4. Summary of key points of wait, notify, notifyAll

  1. wait/notify/notifyAll are all methods of Object, so as long as it is a class object, you can use wait, notify, and notifyAll.
  2. wait/notify/notifyAll should be used with synchronized. If used without synchronized, an exception will be thrown directly:IllegalMonitorStateException
  3. The synchronized lock object must be the same object that calls the wait/notify/notifyAll method.
  4. For a locked object, first execute wait and then notify/notifyAll, and then it will have an effect. If there is no wait, notify is equivalent to "killing it all with one shot". At this time, wait cannot wake up, but no other exceptions will occur in the code.

5. Wait/notify usage example

public class ThreadExample_wait_notify {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        Object object = new Object();
        Thread t1 = new Thread(()->{
    
    
           synchronized (object) {
    
    
               try {
    
    
                   System.out.println("wait开始");
                   object.wait();
                   System.out.println("wait结束");
               } catch (InterruptedException e) {
    
    
                   e.printStackTrace();
               }
           }
        });

        Thread t2 = new Thread(()->{
    
    
           synchronized (object) {
    
    
               System.out.println("notify开始");
               object.notify();
               System.out.println("notify结束");
           }
        });
        // 等待t1中wait解锁阻塞,否则t2中的notify没有实质效果
        t1.start();
        Thread.sleep(1000);
        t2.start();
    }
}

Description of results:

The above code t1 acquires the lock first. When wait is executed, t1 blocks and unlocks. After 1 second, t2 acquires the lock. When notify is executed, the t1 thread will be awakened, but the lock will not be released immediately after notify. When the t2 code block The lock is released only after the logic is executed, and the t1 thread can acquire the lock and continue execution.

3. Wait, join, sleep summary

(1) The wait
wait()method isObject classThe provided instance method can put the thread into a waiting state until other threads call the notify() or notifyAll() method of the object. It is usually used for inter-thread communication, such as in the producer-consumer model (described later), where the consumer needs to wait for the producer to notify that new data is available. When a thread calls the wait() method, it releases the occupied lock, and the thread's status is WAITING until the notify() or notifyAll() method is called.

(2) The join
join()method isMethods provided by Thread class Static methods, used to wait for the called thread to complete execution. After calling the join() method of the sub-thread in the main thread, the main thread will enter the WAITING state and will not continue execution until the sub-thread completes execution. Can be used to ensure that multiple threads execute in a specified order.

(3) The sleep
sleep()method is alsoInstance methods provided by Thread class, which can cause the current thread to pause execution for a period of time. When a thread calls the sleep() method, it does not release the lock and the thread's status is TIMED_WAITING. Usually used to control the speed or time of program execution, or often inside a loop to wait for certain conditions to occur.

In general,The wait() method is used for communication between threadsThe join() method is used to wait for other threads to complete executionThe sleep() method is used to pause the execution of the current thread. In terms of use, wait needs to be used with synchronized, but sleep and join do not. In short, there is essentially no comparability. The only similarity is that they can let the thread give up execution for a period of time. their useScenesDifferent, you need to choose the appropriate method according to actual needs.

Guess you like

Origin blog.csdn.net/LEE180501/article/details/130457892