当前位置: 首页 > article >正文

多线程篇五——wait和notify

多线程篇五——wait和notify

如笔者理解有误,欢迎交流指正⭐


线程的执行先后顺序难以预料【抢占式执行】,但是实际开发中我们会需要掌握当下线程的执行顺序.
这就是wait和notify的作用.【都是Object方法即随便定义一个对象豆可以使用wait和notify】

wait()方法
wait执行过程

1.释放当前的锁
2.让线程进入阻塞
3.当线程被唤醒的时候重新获取到锁

上代码

public class Demo15 {
    public static void main(String[] args) throws InterruptedException {
        Object object = new Object();
        synchronized (object) {
            System.out.println("waiting...");
            object.wait();
            System.out.println("end.");
        }
    }
}

运行发现wait一直处于等待状态

1

tips
wait搭配synchronized使用,synchronized加锁给对象头进行标记

wait结束等待的条件

其他线程调用该对象的notify方法
wait等待超时(timeout用来指定等待时间)
其他线程调用该等待线程的interrupted方法,抛出InterruptedException异常

wait和sleep的对比
共同点

让线程在一段时间里不执行.【wait用于线程间通信(生产者-消费者模型) sleep用于线程阻塞(延迟操作)】

不同点

1.wait()可通过notify()唤醒,sleep()通过Interrupt()唤醒
2.使用wait()时没有设置最大等待时间,而sleep()是在知道最大时限的情况下使用(通过异常唤醒,说明程序应该是出现特殊情况了).
3.wait()搭配synchronized使用,sleep()不用.
4.wait()是Object的方法,sleep()是Thread的静态方法.
5.wait()方法会释放锁,sleep()不会.

notify()方法

此时我们的notify()方法就担起了唤醒wait()方法的大任(唤醒等待的线程).
tips
notify()要在同步方法或同步块中调用.它会通知可能等待该对象对象锁的其他线程,使得它们重新获取对象锁.
如果有多个线程等待,有线程调度器随机挑选一个wait状态的线程[【无先来后到】
调用notify()方法后不会立即释放对象锁,要等到执行notify()方法的线程将程序执行完之后【退出同步代码块】才会释放对象锁.

notify唤醒线程过程

1.创建 WaitTask 类, 对应一个线程, run 内部循环调用 wait.
2.创建 NotifyTask 类, 对应另一个线程, 在 run 内部调用一次 notify 注意, WaitTask 和 NotifyTask 内部持有同一个 Object locker.
3.WaitTask 和 NotifyTask 要想配合 就需要搭配同一个 Object.

public class Demo16 {
        public static Object locker = new Object();

        public static void main(String[] args) {
            Thread t1 = new Thread(() -> {
                synchronized (locker) {
                    System.out.println("t1 wait 之前");
                    try {
                        //t1执行到这,就会先立即释放锁,进入wait方法(释放锁+阻塞等待)
                        locker.wait();
                        System.out.println("t1 wait 之后");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });

            Thread t2 = new Thread(() -> {
                try {
                    //t2执行起来之后,先进行sleep(3000)(这个sleep操作就可以让t1先拿到锁)
                    //如果先notify虽然不会有副作用(不会出现异常之类的),但是wait就无法被唤醒,逻辑上有问题
                    Thread.sleep(3000);
                    //t2sleep结束之后,由于t1是wait状态,t2就能拿到锁
                    //接下来打印t2notify之前,执行notify操作,这个操作就能唤醒t1(此时t1就从WAITING状态恢复过来了)
                    synchronized (locker) {
                        System.out.println("t2 notify 之前");
                        locker.notify();
                        //但是由于t2此时还没有释放锁,WAITING恢复之后,尝试获取锁,就可能出现一个小小的阻塞,这个阻塞是由锁竞争引起的
                        //t1目前处于BLOCKED状态,但是时间比较短,肉眼看不见
                        System.out.println("t2 notify 之后");
                    }
                    //t2释放锁之后,就可以继续执行t1
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            t1.start();
            t2.start();
        }
    }
notifyAll()方法

顾名思义哈 notifyAll()可以唤醒所有方法>
注意
唤醒的这些方法在等待(wait)返回时重新获取锁产生锁竞争,但实际这些锁是串行执行的【锁被哪个线程先获取是不确定的】

区别notify()和notifyAll()

1.唤醒一个/都唤醒
2.没有锁竞争/产生锁竞争
对比可发现notify()比notifyAll()好控制 发生错误的概率更低

未完待续❀❀❀


http://www.kler.cn/a/300934.html

相关文章:

  • 10 为什么系统需要引入分布式、微服务架构
  • 以太网实战AD采集上传上位机——FPGA学习笔记27
  • opencv进行人脸识别环境搭建
  • Outlook 无网络连接[2604] 错误解决办法
  • springboot程序快速入门
  • vue中的那些事(刷新+key+v-if,v-for)
  • 现货黄金避险属性是怎么来的?
  • 敏捷开发方法例题
  • 从用户反馈看相亲交友平台的设计缺陷及改进方向
  • 电脑开机速度慢怎么解决?
  • 【智能终端】HBuilder X 与微信开发者工具集成与调试实战
  • Windows系统下安装Redis
  • EasyExcel相关整理
  • 【C++登堂入室】类和对象(中)——类的6个默认成员函数
  • 外包干了三年,快要废了。。。
  • Vulnhub-RickdiculouslyEasy靶场(9个flag)
  • Go语言中的RPC协议原理解析
  • Redis中的AOF重写过程及其实际应用
  • 再次进阶 舞台王者 第八季完美童模全球赛荣耀大使【梅释尹】赛场秀场超燃合集!
  • React尚硅谷020-036(props、ref、受控组件)
  • 【HarmonyOS】鸿蒙头像上传-(编辑个人信息页- 头像上传)+实时数据更新
  • 【9.11最新发布】Win10 22H2 19045.4894 正式版镜像!
  • c-项目(公交调度子系统)
  • 08-图7 公路村村通(C)
  • C#简单计算机项目(优化后版本)
  • JVM 调优篇3 jvm对象的内存布局与执行引擎