多线程等待唤醒机制

三个方法

调用需注意细节

实例

等待唤醒机制就是⽤于解决线程间通信的问题的,使⽤到的3个⽅法的含义如下:

  1. wait:线程不再活动,不再参与调度,进⼊ wait set 中,因此不会浪费 CPU 资源,也不会去竞争锁 了,这时的线程状态即是 WAITING。它还要等着别的线程执⾏⼀个特别的动作,也即是“通知( notify )”在这个对象上等待的线程从 wait set 中释放出来,重新进⼊到调度队列( ready queue )中。
  2. notify:则选取所通知对象的 wait set 中的⼀个线程释放;例如,餐馆有空位置后,等候就餐最久的 顾客最先⼊座。
  3. notifyAll:则释放所通知对象的 wait set 上的全部线程。

调⽤wait和notify⽅法需要注意的细节

  1. wait⽅法与notify⽅法必须要由同⼀个锁对象调⽤。因为:对应的锁对象可以通过notify唤醒使⽤同⼀ 个锁对象调⽤的wait⽅法后的线程。
  2. wait⽅法与notify⽅法是属于Object类的⽅法的。因为:锁对象可以是任意对象,⽽任意对象的所属 类都是继承了Object类的。
  3. wait⽅法与notify⽅法必须要在同步代码块或者是同步函数中使⽤。因为:必须要通过锁对象调⽤这2 个⽅法。

实例一:

包⼦铺线程⽣产包⼦,吃货线程消费包⼦。当包⼦没有时( 包⼦状态为false ),吃货线程等待,包⼦铺线程⽣产 包⼦( 即包⼦状态为true ),并通知吃货线程( 解除吃货的等待状态 ),因为已经有包⼦了,那么包⼦铺线程进 ⼊等待状态。接下来,吃货线程能否进⼀步执⾏则取决于锁的获取情况。如果吃货获取到锁,那么就执⾏吃包⼦动 作,包⼦吃完( 包⼦状态为false ),并通知包⼦铺线程( 解除包⼦铺的等待状态 ),吃货线程进⼊等待。包⼦ 铺线程能否进⼀步执⾏则取决于锁的获取情况。

包子资源类:
package Thread_a;
public class BaoZi {
    private int count = 1;
    private boolean flag = false;

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }
}

package Thread_a;

//测试类
public class BoziText {
    public static void main(String[] args) {
        BaoZi bz = new BaoZi();

        ChiHuo chiHuo = new ChiHuo(bz);
        BoZiPu boZiPu = new BoZiPu(bz);

        chiHuo.start();
        boZiPu.start();
    }
}

//吃货线程类
class ChiHuo extends Thread{
    private BaoZi bz;

    public ChiHuo(BaoZi bz) {
        this.bz = bz;
    }

    public void run(){
        while (bz.getCount() < 10) {
            synchronized (bz) {
                if (bz.isFlag() == false) {
                    System.out.println("包子吃完了>>没有包子了");
                    try {
                        bz.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                System.out.println("吃货吃包子>>包子吃完了");
                bz.setFlag(false);
                bz.setCount(bz.getCount()+1);
                System.out.println("包子吃完了>>");
                //唤醒等待线程(包子铺)
                bz.notify();
            }
        }
        System.out.println("吃货吃饱了");
    }

}

//包子铺线程类
class BoZiPu extends Thread{
    private BaoZi bz;

    public BoZiPu(BaoZi bz) {
        this.bz = bz;
    }

    public void run(){
        while (bz.getCount()<10) {
            synchronized (bz) {
                if (bz.isFlag() == true) {
                    System.out.println("还有包子>>吃货吃包子");
                    try {
                        bz.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                System.out.println("没有包子>>第"+bz.getCount()+"次开始制作包子");
                bz.setFlag(true);
                System.out.println("包子做好了");
                //唤醒等待线程(吃货)
                bz.notify();

            }
        }

    }
}


实例二:

// 需求: 两个线程 wait notify
// 线程1: 图片的加载 1% ~ 100% 图片的下载 1%~100%
// 线程2: 图片的显示 显示
// 同时开启线程: 显示之前 需要 加载完成
// 显示后 才能开始下载

package a_communication;

public class Demo2 {
    public static void main(String[] args) {
        String str = "这是用来做加锁的工具的, 此案例中什么意义都没有";
        ShowTask show = new ShowTask(str);
        LoadTask load = new LoadTask(str);
        Thread loadThread = new Thread(load);

        show.start();
        loadThread.start();
    }
}
// 显示的线程: 第一种线程创建的方式
class ShowTask extends Thread {
    private String obj;

    public ShowTask(String obj) {
        this.obj = obj;
    }

    public void run() {
        System.out.println("等待加载...");

        synchronized (obj) {
            try {
                obj.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        System.out.println("显示图片");

        // 显示后可以下载, 唤醒下载线程
        synchronized (obj) {
            obj.notify();
        }
    }
}
// 加载 + 下载的线程: 第二种创建线程的方式
class LoadTask implements Runnable {
    private String obj;

    public LoadTask(String obj) {
        this.obj = obj;
    }

    @Override
    public void run() {
        System.out.println("开始加载");
        for (int i = 0; i < 10; i++) {
            System.out.println("正在加载: " + i + "%");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("加载完成, 等待显示..");
        synchronized (obj) {
            // 唤醒显示的线程 -> 显示的线程是进入到了就绪状态
            obj.notify();
        }

        synchronized (obj) { // 等待显示完成
            try {
                obj.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        System.out.println("开始下载");
        for (int i = 0; i < 10; i++) {
            System.out.println("正在下载: " + i + "%");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("下载完成, 结束!");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值