Multi-threaded waiting notification mechanism

table of Contents
  • What is the waiting notification mechanism
  • Waiting for the realization of the notification mechanism
  • notify will not release the lock object immediately
  • interrupt will interrupt the waiting of the thread
  • The difference between notify and notifyAll
  • Use of wait (Long)

What is the waiting notification mechanism

Coupon platform https://www.cqfenfa.com/

In a single thread, the operation to be executed needs to meet certain conditions before it can be executed. You can put this operation in an if statement block.

In multi-threaded programming, the condition of thread A may not be satisfied but only temporarily. Later other threads B may update the condition so that the condition of thread A is satisfied. Thread A can be suspended until its conditions are met. A thread wake up

Atomic{
 while(条件不成立)
 {
 等待
 }
 条件满足后,当前线程被唤醒
}

Waiting for the realization of the notification mechanism

The Wait method in the object class can make the current thread's code suspend execution until notified or interrupted

note:

(1) The wait method can only be called by the lock object in the synchronization code block

(2) Call the wait method, the current thread will release the lock

public class Text16_5 {
    public static void main(String[] args) throws InterruptedException {
        String text="hello";
        System.out.println("同步前代码块");
        synchronized (text)
        {
            System.out.println("同步代码块开始");
            text.wait();
            System.out.println("同步代码块结束");
        }
        System.out.println("全部结束");
    }
}

image-20210316211333325

Because the wait method of the lock object is called, the lock object is released, and it is in a waiting state, and it will wait forever if it is not awakened.

The notify method of the object class can wake up the thread. This method must also be synchronized in the code block. It is called by the lock object. Calling wait/notify without using the lock object will report the IiegalMonuitorStateExeption exception. If there are multiple waiting threads, the notify method can only Wake up one of them. After calling the notify method in the synchronized code block, the lock object will not be released immediately. The lock object will not be released until the current synchronized code block is executed. Generally, notify is placed at the end of the synchronized code block.

synchronized(锁对象)
{
  //执行修改保护条件的代码
  //唤醒其他线程
  锁对象.notify();
}
public class TextNotify {
    public static void main(String[] args) throws InterruptedException {
        String text="hello";
        Thread t1=new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (text)
                {
                    System.out.println("同步代码块开始");
                    try {
                        text.wait();//线程等待 
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("同步代码块结束");
                }
            }
        });
        Thread t2=new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (text)
                {
                    System.out.println("线程开始唤醒");
                    text.notify();
                    System.out.println("线程结束唤醒");
                }
            }
        });
        t1.start();//开启t1线程 t1等待
        Thread.sleep(3000);//睡眠3秒 确保t1处于等待状态
        t2.start();//唤醒t1线程
    }
}

image-20210316214002434

notify will not release the lock object immediately

Case:

import java.util.ArrayList;
import java.util.List;

public class NotifyText2 {
    public static void main(String[] args) throws InterruptedException {
        List<String> strings=new ArrayList<>();
        Thread t1=new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (strings)
                {
                    System.out.println("线程1开始等待");
                    try {
                        strings.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("线程1被唤醒");
                }
            }
        });
        Thread t2=new Thread(new Runnable() {
            @Override
            public void run() {
               synchronized (strings)
               {
                   for (int i = 0; i <10 ; i++) {
                       strings.add("data"+i);
                       System.out.println("线程2添加了"+(i+1));
                       if(strings.size()==5)
                       {
                           strings.notify();
                           System.out.println("线程2被唤醒");
                       }
                   }
               }
            }
        });
        t1.start();
        Thread.sleep(1000);
        t2.start();
    }
}

The code of thread 2 has not been executed yet, and the lock is still being executed without being released immediately. You need to wait until all code blocks are executed before releasing it.

image-20210316220423289

interrupt will interrupt the waiting of the thread

public class InterruptText {
    private static  final String name=new String();
    public static void main(String[] args) throws InterruptedException {

        Thread t1=new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (name)
                {
                    try {
                        System.out.println("同步代码块开始");
                        name.wait();
                        System.out.println("同步代码块结束");
                    } catch (InterruptedException e) {
                        System.out.println("wait被中断"+e);
                    }
                }
            }
        });
        t1.start();
        Thread.sleep(2000);
        t1.interrupt();
    }
}

It turns out that the lock object needs to execute the synchronization code block to release the lock object. If an exception is encountered during the execution process, the thread will be terminated and the lock object will be released. Calling the wait method will also release the lock object.

image-20210317202003190

The difference between notify and notifyAll

Notify can only wake up one at a time. If multiple threads are waiting, only one of them can be awakened randomly. To wake up all waiting threads, notifyAll needs to be called.

public class InterruptText {
    private static  final String name=new String();
    public static void main(String[] args) throws InterruptedException {
        String str=new String();
        NotifyAll notifyAll=new NotifyAll(str);
        NotifyAll notifyAl2=new NotifyAll(str);
        NotifyAll notifyAll3=new NotifyAll(str);
        notifyAll.setName("线程一");
        notifyAl2.setName("线程二");
        notifyAll3.setName("线程三");
        notifyAll.start();
        notifyAl2.start();
        notifyAll3.start();
        Thread.sleep(2000);//休眠两秒
        synchronized (str)
        {
            //str.notify();只能随机唤醒一个
            str.notifyAll();//唤醒全部线程
        }
    };
     static class NotifyAll extends Thread
    {
        private    String name;
        private  NotifyAll(String name)
        {
            this.name=name;
        }
                @Override
                public void run() {
                    synchronized (name)
                    {
                        try {
                            System.out.println(Thread.currentThread().getName()+"同步代码块开始");
                            name.wait();
                            System.out.println(Thread.currentThread().getName()+"同步代码块结束");
                        } catch (InterruptedException e) {
                            System.out.println("wait被中断"+e);
                        }
                    }
                }

    }
}

image-20210317221240524

If the evil of calling notify() only once can wake up one of the threads, the other waiting threads are still in the waiting state, and the notification signal is missed. This phenomenon is called signal loss.

Use of wait (Long)

Wait (Long) method with parameters, no operation within a specified time will be automatically awakened

Guess you like

Origin blog.csdn.net/nidongla/article/details/115029321