【多线程】之线程通讯wait和notify的使用

原创
2021/06/01 11:16
阅读数 34

1、定义
  等待/通知机制,是指一个线程A调用了对象object的wait()方法进入等待状态,而另一个线程B调用了对象object的notify或者notifyAll()方法,线程A收到通知后从对象O的wait()方法返回,进而还行后续操作。
  使用wait和notify方法实现线程之间的通信,这两个方法是Object类的方法。
  
  注意细节:
  1.1 调用wait()方法,会释放锁,线程状态由RUNNING->WAITNG,当前线程进入对象等待;
  1.2 调用notify()/notifyAll()方法不会立马释放锁,notify()方法是将等待队列中的线程移到同步队列中,而notifyAll()则是全部移到同步队列中,
  被移出的线程状态WAITING-->BLOCKED;
      重点注意,等待队列和同步队列的转换;wait()后进入等待队列;notify()/notifyAll(),线程进入同步队列;
  1.3 当前调用notify()/notifyAll()的线程释放锁了才算释放锁,才有机会唤醒wait线程;
  1.4 从wait()返回的前提是必须获得调用对象锁,也就是说notify()与notifyAll()释放锁之后,wait()进入BLOCKED状态,如果其他线程
  有竞争当前锁的话,wait线程继续争取锁资格。可以理解为,从同步队列中的线程抢占锁执行;
  1.5 使用wait()、notify()、notifyAll()方法时需要先调对象加锁。这就是跟synchronized关键字配置使用;
  
2、代码运行过程

package hake.waitnotifydemo;

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

/**
 * @Author: Liu Yue
 * @Descripition:
 * @Date; Create in 2021/6/1 10:35
 **/
public class Demo {

    private static volatile List list=new ArrayList();

    public static void main(String[] args) {
        final Object lock = new Object();

        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock){
                    System.out.println("thread - 1 线程启动 ***************************");
                    for (int i = 0;i < 10; i++){
                        list.add("thread - 1 - " + i);
                        System.out.println("当前线程"+ Thread.currentThread().getName()+"添加了一个元素");

                        try{
                            Thread.sleep(500);
                            if (list.size()==5){
                                System.out.println("发出唤醒通知********************");
                                lock.notify();
                            }
                        }catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        },"thread - 1");

        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                    synchronized (lock){
                        System.out.println("thread - 2 启动 -------------------------------");
                        if(list.size() != 5){
                            try {
                                lock.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        System.out.println("当前线程:" + Thread.currentThread().getName() + "收到通知线程停止..");
                        throw new RuntimeException();
                    }
            }
        },"thread - 2");

        thread2.start();
        thread1.start();
    }
}

运行代码结果

"C:\Program Files\Java\jdk1.8.0_45\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2018.3.2\lib\idea_rt.jar=49600:C:\Program Files\JetBrains\IntelliJ IDEA 2018.3.2\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_45\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\rt.jar;C:\hake\manager\comhake\target\classes;C:\program\maven-repository\org\codehaus\groovy\groovy\2.5.6\groovy-2.5.6.jar" hake.waitnotifydemo.Demo
thread - 2 启动 -------------------------------
thread - 1 线程启动 ***************************
当前线程thread - 1添加了一个元素
当前线程thread - 1添加了一个元素
当前线程thread - 1添加了一个元素
当前线程thread - 1添加了一个元素
当前线程thread - 1添加了一个元素
发出唤醒通知********************
当前线程thread - 1添加了一个元素
当前线程thread - 1添加了一个元素
当前线程thread - 1添加了一个元素
当前线程thread - 1添加了一个元素
当前线程thread - 1添加了一个元素
当前线程:thread - 2收到通知线程停止..
Exception in thread "thread - 2" java.lang.RuntimeException
	at hake.waitnotifydemo.Demo$2.run(Demo.java:54)
	at java.lang.Thread.run(Thread.java:745)

Process finished with exit code 0

  首先启动thread2线程,使得thread2线程处于等待状态,然后当集合等于5的时候,thread1向thread2线程发出通知,但是并不会释放锁,所以当thread1执行 完毕后,thread2线程才会向下执行。

注意:wait()/nofity()/notifyAll()/ 使用前必须加锁;

相似的功能:

Condition配合Lock实现的等待/通知模式(下一步解析)

LockSupport阻塞park与唤醒unpark方式

每天进步一点点!

 

展开阅读全文
加载中

作者的其它热门文章

打赏
0
0 收藏
分享
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部
返回顶部
顶部