Diagram of Java multithread wait() and notify() methods

Detailed explanation of multithreaded wait() and notify() methods


foreword

Blogger's Personal Community: Development and Algorithm Learning Community

Blogger Profile: Killing Vibe's Blog

Everyone is welcome to join and exchange and learn together~~


1. Inter-thread waiting and wake-up mechanism

wait() and notify() are methods of the Object class , which are used to wait and wake up threads, and must be used with synchronized locks .

In a multi-threaded concurrent scenario, sometimes some threads need to be executed first, and other threads will continue to execute after the execution of these threads is completed.

For example: in a long-distance race, the referee has to wait for the runners to cross the line before declaring the end of the race. Then the referee thread has to wait for all the runner threads to finish running before waking up the referee thread.

Second, the waiting method wait()

What wait does:

  • Make the thread currently executing the code wait . (Put the thread in the waiting queue)
  • release the current lock
  • Wake up when certain conditions are met, and try to acquire the lock again.

wait should be used with synchronized. Using wait without synchronized will directly throw an exception.

insert image description here

The conditions for wait to end waiting:

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

Precautions:

  1. The premise of calling the wait() method is to first acquire the lock of the object (synchronize object lock)

  2. Calling the wait() method will release the lock . This thread enters the waiting queue and waits to be awakened. After being awakened, it does not resume execution immediately, but enters the blocking queue , competing for the lock

Wait method:

1. Idiot method, dead, etc., the thread enters the blocking state (WAITING) until other threads call the notify method to wake up

insert image description here

2. Wait for a period of time. If the thread is awakened within this time, it will continue to execute. If no other thread wakes up the thread beyond the corresponding time, the thread will not wait and resume execution.

insert image description here

After calling the wait method:

insert image description here

3. The wake-up method notify()

The notify method is to wake up the waiting thread.

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

Precautions:

  • notify(): Randomly wakes up a thread in a waiting state.
  • notifyAll(): Wake up all waiting threads.
  • Both wait and notify methods need to be used with synchronized locks (waiting and waking up also require objects)

insert image description here

Fourth, about wait and notify internal waiting issues (important)

For the wait and notify methods, there is actually a blocking queue and a waiting queue .

  • The blocking queue means that only one thread can acquire the lock at the same time, and other threads enter the blocking queue

  • The waiting queue means calling wait (first, this thread needs to acquire the lock, enter the waiting queue, and release the lock )

Take a chestnut:

There is an existing waiting thread task defined as follows

private static class WaitTask implements Runnable {
    
    
        private Object lock;
        public WaitTask(Object lock) {
    
    
            this.lock = lock;
        }
        @Override
        public void run() {
    
    
            synchronized (lock) {
    
    
                System.out.println(Thread.currentThread().getName() + "准备进入等待状态");
                // 此线程在等待lock对象的notify方法唤醒
                try {
    
    
                    lock.wait();
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
    
    
                    throw new RuntimeException(e);
                }
                System.out.println(Thread.currentThread().getName() + "等待结束,本线程继续执行");
            }
        }
    }

Then create three waiting threads:

insert image description here

Since only one thread (random scheduling) can acquire the synchronized lock at the same time, there will be two threads that do not compete for the lock and thus enter the blocking queue .

Here, if t2 competes for the lock first, it will block t1 and t3 first:

insert image description here

And because calling the wait method will release the lock , the thread t2 calling the wait method will enter the waiting queue until it is awakened by notify or automatically awakened by a timeout.

insert image description here

Then the lock object has been released at this time, so t1 and t3 can compete for the lock again, and compete for the lock from the blocking queue.

Here, if t3 competes for the lock, only t1 is left in the blocking queue :

insert image description here

Then t3 runs to the wait method, releases the lock, and enters the waiting queue :

insert image description here

Then repeat these operations~~, and finally t1, t2, t3 all enter the waiting queue , waiting for the notify thread to wake up ( here, it is assumed that the notify should be placed several seconds after the start of these threads, because the notify thread is also executed concurrently with these threads , so the threads in the waiting queue may be woken up at any time )

insert image description here

Here comes the point:

After the thread in the waiting queue is awakened by notify, it will directly return to the blocking queue to compete for the lock! ! ! Instead of directly waking up~

Take a chestnut:

Take notifyAll() as an example. If there are three threads t1, t2, and t3 in the waiting queue at this time, calling notifyAll() will directly put them into the blocking queue from the waiting queue :

insert image description here

Then compete for the lock and execute the code after wait~~

5. Complete code (for testing only)

private static class WaitTask implements Runnable {
    
    
        private Object lock;
        public WaitTask(Object lock) {
    
    
            this.lock = lock;
        }
        @Override
        public void run() {
    
    
            synchronized (lock) {
    
    
                System.out.println(Thread.currentThread().getName() + "准备进入等待状态");
                // 此线程在等待lock对象的notify方法唤醒
                try {
    
    
                    lock.wait();
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
    
    
                    throw new RuntimeException(e);
                }
                System.out.println(Thread.currentThread().getName() + "等待结束,本线程继续执行");
            }
        }
    }
    private static class NotifyTask implements Runnable {
    
    
        private Object lock;
        public NotifyTask(Object lock) {
    
    
            this.lock = lock;
        }
        @Override
        public void run() {
    
    
            synchronized (lock) {
    
    
                System.out.println("准备唤醒");
                // 唤醒所有线程(随机)
                lock.notifyAll();
                System.out.println("唤醒结束");
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
    
    
        Object lock = new Object();
        Object lock2 = new Object();
        // 创建三个等待线程
        Thread t1 = new Thread(new WaitTask(lock),"t1");
        Thread t2 = new Thread(new WaitTask(lock),"t2");
        Thread t3 = new Thread(new WaitTask(lock),"t3");
       // 创建一个唤醒线程
        Thread notify = new Thread(new NotifyTask(lock2),"notify线程");
        t1.start();
        t2.start();
        t3.start();
        ;
        Thread.sleep(100);
        notify.start();
        // 当前正在执行的线程数
        Thread.sleep(2000);
        System.out.println(Thread.activeCount() - 1);
    }

Six, the difference between wait and sleep methods (interview questions):

  1. The wait method is a method provided by the Object class. It needs to be used with a synchronized lock. Calling the wait method will release the lock, and the thread will enter the WAITING state, waiting to be awakened by other threads or automatically awakened by a timeout. After awakening, the thread needs to compete for the synchronized lock again to continue execution. .
  2. The sleep method is a method provided by the Thread class. The thread that calls the sleep method enters the TIMED_WAITING state, does not release the lock, and wakes up automatically when the time is up.

Summarize

The above is the detailed explanation and precautions of the wait and notify methods in the multi-threaded scenario. The code word is not easy. If it is helpful, don’t forget to follow the blogger, like + bookmark ~

Guess you like

Origin blog.csdn.net/qq_43575801/article/details/127601039