Java multithreaded wait() and notify() and notifyAll()

wait

wait()

The thread that calls this method enters the WAITING state and will only return when it waits for another thread’s notification or is interrupted. It should be noted that after calling the wait() method, the object’s lock will be released, "until other threads call the object’s notify() method Or notifyAll() method", the current thread is awakened (into the "ready state"), wait() needs to be wrapped in the synchronized code block

When a thread wakes up from the wait() method of the object, it will compete for the lock again. When the contention is reached, the condition will be checked, and if it is established, the following business logic will be performed.

wait(long)
makes the current thread in a "waiting (blocking) state", "until other threads call the notify() method or notifyAll() method of this object, or the specified amount of time is exceeded", the current thread is awakened (into the "ready status").

The parameter time here is milliseconds, that is, wait up to n milliseconds

wait (long, int)
For finer-grained control of the timeout period, it can reach nanoseconds

Wait/notify mechanism

The notify/notifyAll and wait methods, when using these three methods, must be in the synchronized code block or synchronized method, otherwise an IllegalMonitorStateException will be thrown. This is because the monitor of the current object must be obtained before calling these methods The monitor object, which means that the notify/notifyAll and wait methods depend on the monitor object. In the previous analysis, we know that the monitor exists in the Mark Word of the object header (stores the monitor reference pointer), and the synchronized keyword can get the monitor. This That is why the notify/notifyAll and wait methods must be called in the synchronized code block or synchronized method.

notify()和notifyAll()

Notify a thread waiting on the object to return from the wait method, and the premise of the return is that the thread has acquired the lock of the object, and the thread that has not acquired the lock reenters the WAITING state.

notify()

After the thread calls notify() or notifyAll(), the thread will not release its own lock until the synchronized package method is executed, it will release the lock, so notify() and notifyAll() are generally placed in the synchronized code block Last line

notify() and notifyAll() need to wrap the synchronized code block

The difference between notify and notifyAll in Java

Wake up the waiting threads on the current object; notify() is to wake up a single thread, and notifyAll() is to wake up all threads.

When you call notify, only one waiting thread will be awakened and it cannot guarantee which thread will be awakened, depending on the thread scheduler. Although if you call the notifyAll method, all threads waiting for the lock will be awakened, but before executing the remaining code, all awakened threads will compete for the lock, which is why wait is called on the loop, because if multiple threads Was awakened, then the thread will get the lock and will execute first, it may reset the waiting condition, which will force subsequent threads to wait. Therefore, the key difference between notify and notifyAll is that notify() will only wake up one thread, while the notifyAll method will wake up all threads.

When to use notify and notifyAll in Java

If all threads are waiting for the same condition, and only one thread can go from the condition to true at a time, you can use notify over notifyAll.

In this case, notify is better than notifyAll because we wake up all of these because we know that only one thread will benefit and all other threads will wait again, so calling the notifyAll method just wastes CPU.

Use notifyall() as much as possible. Use notify() with caution, because notify() will only wake up one thread. We cannot ensure that the thread that is woken up must be the thread we need to wake up. Maybe the thread I want to wake up is not notified.

The notify/notifyAll and wait methods, when using these three methods, must be in the synchronized code block or synchronized method, otherwise an IllegalMonitorStateException will be thrown. This is because the monitor of the current object must be obtained before calling these methods The monitor object, which means that the notify/notifyAll and wait methods depend on the monitor object. In the previous analysis, we know that the monitor exists in the Mark Word of the object header (stores the monitor reference pointer), and the synchronized keyword can get the monitor. This That is why the notify/notifyAll and wait methods must be called in the synchronized code block or synchronized method.

wait and Notify code demo


 

/**
 * 先下载图片,图片下载展示附件 ,
 * 再下载附件
 */
public class Demo1 {
    
    


   public static void main(String[] args) {
    
    

      Object obj = new Object();

      Thread download = new Thread("我是下载线程 :") {
    
    
         @Override
         public void run() {
    
    

            System.out.println(this.getName() + "***开始下载图片");
            for (int i = 0; i < 101; i += 50) {
    
    
               System.out.println(this.getName() + "下载进度 : " + i + "%");
               try {
    
    
                  Thread.sleep(50);
               } catch (InterruptedException e) {
    
    
               }
            }
            System.out.println(this.getName() + "***图片下载成功");

            synchronized (obj) {
    
    
               obj.notify(); //唤醒线程
               System.err.println(this.getName() + "我释放了我自己的锁");
            }

            System.out.println(this.getName() + "***开始下载附件");
            for (int i = 0; i < 101; i += 50) {
    
    
               System.out.println(this.getName() + "附件下载进度 : " + i + "%");
            }
            try {
    
    
               Thread.sleep(50);
            } catch (InterruptedException e) {
    
    
               e.printStackTrace();
            }
            System.out.println(this.getName() + "***附件下载成功");
         }
      };
      //图片展示

      Thread show = new Thread("我是查看线程 :") {
    
    
         @Override
         public void run() {
    
    
            synchronized (obj) {
    
    
               try {
    
    
                  obj.wait();//阻塞线程等图片下载完毕
               } catch (InterruptedException e) {
    
    
                  e.printStackTrace();
               }
               System.out.println(this.getName() + "***开始展示图片");
               System.out.println(this.getName() + "***图片展示完毕");


            }
         }
      };
      /*即使是 展示线程先启动,如果图片没下载完了,也不让你展示, 让你优先运行下载线程*/


      /*同时启动两个线程,然后show线程开始等待状态,等待下载线程下载完毕之后才开启线程*/
      download.start();
      show.start();


   }

}

Guess you like

Origin blog.csdn.net/qq_41489540/article/details/109158287