抓饭直播致力于服务大众球迷,提供高清足球直播、NBA直播、世界杯直播等,让体育赛事能给更多热爱的人免费观看,全站点赛事无需会员,无需插件,收集全网最稳定的直播链接提供给全国球迷。联系我们
  • 07-21 11:00 新西兰联
    坎特伯雷公羊 塔拉纳基
    坎特伯雷公羊 vs 塔拉纳基
    0 0
  • 07-21 23:30 秘后备
    秘鲁体育大学后备队 卡哈马卡后备队
    秘鲁体育大学后备队 vs 卡哈马卡后备队
    0 0
  • 07-21 23:30 乌拉甲
    普罗格雷索俱乐部 马尔多纳多
    普罗格雷索俱乐部 vs 马尔多纳多
    0 0
  • 07-21 23:00 智利女甲
    U康塞普森女足 帕莱斯蒂诺女足
    U康塞普森女足 vs 帕莱斯蒂诺女足
    0 0
  • 07-21 22:30 球会友谊
    SV阿特拉斯代 BV加瑞尔
    SV阿特拉斯代 vs BV加瑞尔
    0 0
  • 07-21 22:00 阿全甲
    坦迪尔 罗森
    坦迪尔 vs 罗森
    0 0
  • 07-21 21:30 球会友谊
    本菲卡 比利亚雷亚尔
    本菲卡 vs 比利亚雷亚尔
    0 0
  • 07-21 21:00 乌拉甲
    蒙得维的亚 塞路
    蒙得维的亚 vs 塞路
    0 0
  • 07-21 21:00 乌拉乙
    阿尔比恩 雷提斯塔
    阿尔比恩 vs 雷提斯塔
    0 0
  • 07-21 20:30 印尼总杯
    佩西加雅加达 马都拉联
    佩西加雅加达 vs 马都拉联
    0 0
  • 07-21 20:00 球会友谊
    云达不莱梅女足 亨施泰特乌尔茨堡女足
    云达不莱梅女足 vs 亨施泰特乌尔茨堡女足
    0 0
  • 07-21 20:00 球会友谊
    阿尔克马尔女足 科隆女足
    阿尔克马尔女足 vs 科隆女足
    0 0
  • 07-21 19:30 球会友谊
    圣吉罗斯 利尔斯
    圣吉罗斯 vs 利尔斯
    0 0
  • 07-21 17:00 球会友谊
    彭祖约 伊彼图
    彭祖约 vs 伊彼图
    0 0
  • 07-21 16:30 印尼总杯
    巴厘联 阿雷马
    巴厘联 vs 阿雷马
    0 0
抓饭直播 > 体育新闻 > 电竞新闻 > >亚瑟yase(张小飞的Java之路——第二十四章——多线程——wait_notify)

亚瑟yase(张小飞的Java之路——第二十四章——多线程——wait_notify)

2023-09-22 00:40

写在前面:

视频是什么东西,有看文档精彩吗?

视频是什么东西,有看文档速度快吗?

视频是什么东西,有看文档效率高吗?



诸小亮:下面我们聊聊——线程通信技术

张小飞:多个线程之间还可以通信吗?

诸小亮:是的,通过调用锁对象的wait()、notify()方法,可以实现线程通信

张小飞:那具体如何使用呢?

1. 体验

诸小亮:首先,Object 类中有 wait()、notify() 这两个方法

  • wait():让当前线程进入等待状态
    • 使用方式:锁对象.wait(),必须放到 同步代码块 或 同步方法 中
  • notify():唤醒对应的正在 wait 的线程
    • 使用方式:锁对象.notify(),必须放到 同步代码块 或 同步方法 中
  • 调用 wait() 和 notify() 的锁对象必须是同一个

张小飞:大概明白,不过还需要您给出具体的代码

诸小亮:代码也给你准备好了,注意代码中的注释

class Hero implements Runnable{    //1. 搞一个锁对象    public static Object lock = new Object();    @Override    public void run(){        synchronized (lock){            System.out.println(Thread.currentThread().getName() + "。。。。。。。获取锁,然后进入等待状态");            try {                //2. 让当前线程等待,使用方式:锁对象.wait(),而且必须放到同步代码块或者同步方法中                lock.wait();            } catch (InterruptedException e) { }            System.out.println(Thread.currentThread().getName() + "。。。。。。。结束");        }    }}public class ThreadDemo {    public static void main(String[] args) throws Exception {        //3. 创建一个 yase 线程        Thread yase = new Thread(new Hero(),"yase");        yase.start();        //4. 主线程休眠2秒        Thread.sleep(2000);        //5. 使用notify唤醒yase线程,让他继续执行        synchronized (Hero.lock){            System.out.println("主线程唤醒yase。。。。。。。");            //使用方式:锁对象.notify(),唤醒对应的正在等待状态的线程,必须放到同步代码块或者同步方法中            Hero.lock.notify();        }    }}

结果:

张小飞的Java之路——第二十四章——多线程——wait_notify


诸小亮:你能解释一下这个代码的执行过程吗?

张小飞:当然可以

yase线程先执行,在执行 lock.wait() 代码后,进入等待状态main 线程在休眠 2 秒后,执行 Hero.lock.notify(); 去唤醒 yase 线程yase线程被唤醒后,接着执行,最后输出:yase。。。。。。。结束

诸小亮:不错啊

2. 注意点

诸小亮:使用 wait、notify时,需要特别注意一些地方

张小飞:都需要注意什么?

1. wait、notify必须放到同步代码块或同步方法中

诸小亮:第一,wait、notify必须放到同步代码块或同步方法中

张小飞:哦~,这个刚才说过,不过如果不放到它里面呢?

诸小亮:那调用 wait 方法时就会报错,比如:

张小飞的Java之路——第二十四章——多线程——wait_notify

结果:

张小飞的Java之路——第二十四章——多线程——wait_notify

张小飞:明白了,不过这个异常是?

诸小亮:非法的监控状态异常,线程从启动到死亡有不同的状态,之后会解释

张小飞:好的


2. 锁对象是this

张小飞:如果锁对象是 this 呢?

诸小亮:如果锁对象是this,那么:this.wait(),记住必须是:锁对象.wait(),否则:

张小飞的Java之路——第二十四章——多线程——wait_notify

上图,锁对象是this,但是却调用 lock.wait();,结果:

张小飞的Java之路——第二十四章——多线程——wait_notify

张小飞:记住了


3. 锁对象.notify()

张小飞:既然必须是 锁对象.wait(),那么也肯定必须是:锁对象.notify()

诸小亮:没错,否则也会报错,比如:

张小飞的Java之路——第二十四章——多线程——wait_notify

上图,锁对象是Hero.class,但是却调用Hero.lock.nodify();结果:

张小飞的Java之路——第二十四章——多线程——wait_notify


4. 调用 wait() 和 notify() 的锁对象必须是同一个

诸小亮:还有,调用 wait() 和 notify() 的锁对象必须是同一个,否则:

张小飞的Java之路——第二十四章——多线程——wait_notify

张小飞的Java之路——第二十四章——多线程——wait_notify


结果:

张小飞的Java之路——第二十四章——多线程——wait_notify

张小飞:看输出,程序一直没有结束吧

诸小亮:是的,其原因

  • Hero.class.notify();只能唤醒锁对象是Hero.class 且 执行了 Hero.class.wait() 的线程
  • yase线程的锁对象是lock,执行了lock.wait(),一直在等待被人唤醒,所以程序一直不结束

5. 执行 notify 后,正在 wait 的线程并不是立即运行

张小飞:我发现一个现象

诸小亮:什么现象?

张小飞:执行 notify 后,正在 wait 的线程并不是立即运行,需要等待执行 notify 的线程释放锁

张小飞的Java之路——第二十四章——多线程——wait_notify

结果:

张小飞的Java之路——第二十四章——多线程——wait_notify

诸小亮:嗯,你说的很对,这也是一个需要关注的地方

6. wait()等待时,会释放锁对象

张小飞:还有一个问题,执行 wait() 方法后,是不是就释放锁对象了?

诸小亮:不错,只有释放了锁对象,main线程才能进入 synchronized 代码中

张小飞的Java之路——第二十四章——多线程——wait_notify

上图可以看出,yase先执行,如果wait()不释放锁,那么就无法执行Hero.lock.notify()这句代码


7. 多个线程都在wait(),notify只会随机的唤醒一个

张小飞:如果有多个线程都调用了 wait() 方法呢?

诸小亮:问得好,不过,你何不自己试一试呢?

张小飞:嗯嗯,好的

public static void main(String[] args) throws Exception {    //创建 2 个线程    Thread yase = new Thread(new Hero(),"yase");    yase.start();    Thread laoyase = new Thread(new Hero(),"laoyase");    laoyase.start();    Thread.sleep(2000);        //使用方式:锁对象.notify(),唤醒对应的正在等待状态的线程,必须放到同步代码块或者同步方法中    synchronized (Hero.lock){        System.out.println("主线程唤醒。。。。。。。");        Hero.lock.notify();//有多个线程都在wait(),notify只会随机的唤醒一个    }}

结果:

张小飞的Java之路——第二十四章——多线程——wait_notify


张小飞:结果出来了,yase线程结束了,但是 laoyase 这个线程还在阻塞

诸小亮:其实你多执行几次,会发现——多个线程都在wait(),notify只会随机的唤醒一个

张小飞:好的,我再试试


8. notifyAll()

张小飞:有没有可以把所有都在 wait 中的线程,都唤醒呢?

诸小亮:如果想全部唤醒,可以使用notifyAll(),或者执行多次notify(),比如:

张小飞的Java之路——第二十四章——多线程——wait_notify

结果:

张小飞的Java之路——第二十四章——多线程——wait_notify


另外,执行多次notify()方法也可以,全部唤醒,比如:

张小飞的Java之路——第二十四章——多线程——wait_notify

结果:略


9. 特殊情况下的notify

诸小亮:特殊情况下的 notify 方法会唤醒所有

张小飞:这是什么意思?


诸小亮:来,看代码,注意代码中的注释

class Hero extends Thread{    public void run(){        //1. 注意这里的锁对象是this        synchronized (this){            //2. 执行 notify 唤醒所有            this.notify();            System.out.println("lock线程运行----"+this.getName());        }    }}public class ThreadDemo {    public static void main(String[] args) throws Exception {        //3. 创建一个Thread对象,作为锁对象        Hero yase = new Hero();        yase.setName("yase");        new Thread(new Runnable() {            @Override            public void run() {                System.out.println("线程daji开始运行。。。。。。");                //4. 注意,这里的锁对象是一个线程对象                synchronized (yase){                    try {                        yase.wait();                        System.out.println("线程daji结束----"+yase.getName());//输出lock线程的名称                    } catch (InterruptedException e) {                    }                }            }        }, "daji").start();        new Thread(new Runnable() {            @Override            public void run() {                System.out.println("线程lvbu开始运行。。。。。。");                //4. 注意,这里的锁对象是一个线程对象                synchronized (yase){                    try {                        yase.wait();                        System.out.println("线程vbul结束----"+yase.getName());                    } catch (InterruptedException e) {                    }                }            }        }, "lvbu").start();        Thread.sleep(2000);        //5. 启动 yase 线程        yase.start();    }}

结果:

张小飞的Java之路——第二十四章——多线程——wait_notify


张小飞:这个代码能否具体解释一下?

诸小亮:当然可以

  首先创建一个名为 yase 的线程对象  然后创建了 daji、lvbu 两个线程,这两个线程都把 yase 对象作为锁对象	这两个线程分别启动后都执行 wait 方法,进入等待模式  最后yase线程启动,执行run方法时,调用 this.notify();  结果:daji、lvbu 都被唤醒

张小飞:这是什么原理?

诸小亮:额。。。。,很抱歉我也没仔细研究过,暂时记住这个现象吧

张小飞:好的


3. 生产消费模式

诸小亮:接着我们说一个——生产消费模式

张小飞:这是做什么的?

诸小亮:生产者生产数据,消费者消费数据,先看一张图

张小飞的Java之路——第二十四章——多线程——wait_notify

张小飞:您是先说,面包师生产面包,放到面包柜,然后销售员再取走面包吗?

诸小亮:是的,这就是我们生活中的——生产消费模式


诸小亮:工作中,wait()、notify() 经常用于生产消费模式

张小飞:具体怎么使用呢?

诸小亮:给你一个需求,生产者生产商品,如果货架上已经有商品就不再生产,

消费者消费商品,如果货架上没有就通知生产者

示例:

class Goods{    String name = "哈根达斯";    //0:表示货架上没有商品,需要生产    //1:表示货架上已有商品,需要消费    int count = 0;}//消费者class Consumer implements Runnable{    private Goods goods;    Consumer(Goods goods){        this.goods = goods;    }    @Override    public void run(){        while (true){            synchronized (goods){                if(goods.count == 1){                    System.out.println(Thread.currentThread().getName()+"。。。。。。消费商品---"+goods.count);                    goods.count = 0;//消费商品                    goods.notify();//唤醒消费者                    //让自己自己等待                    try {goods.wait();} catch (InterruptedException e) {}                }            }        }    }}//生产者class Producer implements Runnable{    private Goods goods;    Producer(Goods goods){        this.goods = goods;    }    @Override    public void run(){        while (true){            synchronized (goods){                if(goods.count == 0){                    System.out.println(Thread.currentThread().getName()+"。。。。。。生产商品---------"+goods.count);                    goods.count = 1;//生产商品,设置count=1                    goods.notify();//唤醒消费者                    //自己等待                    try {goods.wait();} catch (InterruptedException e) {}                }            }        }    }}public class ThreadDemo {    public static void main(String[] args) throws Exception {        Goods goods = new Goods();        new Thread(new Producer(goods), "伊利").start();        new Thread(new Consumer(goods), "亚瑟").start();    }}

结果中,两个线程互相唤醒,交替执行

张小飞的Java之路——第二十四章——多线程——wait_notify


诸小亮:怎么样,可以看懂吗?

张小飞:可以可以,原来这就是生产消费模式

4. wait 和 sleep

张小飞:我突然先到,sleep 也是可以暂停线程的

诸小亮:不错, wait 和 sleep 有相同点,也有区别,这也是面试常见的一个问题

张小飞:那么它们都有什么不同的地方呢?

诸小亮:都给你总结好了,自己看看吧

相同点:都可以暂时停止一个线程不同点:	sleep必须指定睡眠时间,wait可以指定也可以不指定	sleep是 Thread 的静态方法,wait是 Object 类的成员方法	sleep 不释放锁,wait 释放锁	sleep 等待一定时间后自定运行,wait需要 notify 或 notifyAll 唤醒	wait 必须配合synchronized使用,sleep不必	sleep 会让线程进入 TIMED_WAITING 状态,wait让线程进入 WAITING 状态(之后会详细解释线程状态)
  • 上一条: 英雄联盟手办(潮趣:《英雄联盟》星之守护者 金克丝 手办 飘动的双马尾)
  • 下一条: 剑灵解印符怎么获得(剑灵副职业讲解之风味门与圣君堂)
  • 声明:本站文章版权归原作者及原出处所有,并不代表本站赞同其观点及真实性,如有侵权,请联系删除。
    耗时0.83秒