【等待唤醒机制】1.以包子铺生产包子,吃货吃包子为例子 2.synchronized+wait+notify

1)线程的6种状态
	NEW(新建状态): 至今尚未启动的线程处于这种状态.

	RUNNABLE(运行状态): 正在java虚拟机中执行的线程处于这种状态.

	BLOCKED(阻塞状态): 受阻塞并等待某个监视器锁的线程处于这种状态.
		等待CPU资源,有则可能执行;
		start后开始争夺CPU的执行资源,没有抢到就进入到阻塞状态;
			获取到锁对象,就进入到运行状态;

	WAITING(无限永久等待状态): 无限期的等待另一个线程来执行某一特定操作的线程处于这种状态.
		冻结状态;

	TIMED_WAITING(休眠(睡眠状态)): 等待另一个线程来执行取决于指定等待时间的操作的线程处于这种状态.
		睡眠,能睡醒,睡醒后,有CPU资源,则执行。 睡眠时,CPU空着也不能执行,必须等待睡醒后;
		也是冻结状态;

	TERMIANTED(死亡状态): 已退出的线程处于这种状态.

2)等待唤醒的案例(也叫线程之间的通信)
	卖包子的商铺:
		消费者
		生产者

	描述: 
		顾客要买包子,和老板说明买包子的数量和种类;
			顾客: 等着老板做包子(调用wait方法-->WAITING状态,无限等待).
			老板: 开始做包子,做好包子,告诉(调用notify方法),顾客包子做好了,就可以开吃了.
			顾客和老板之间形成了一种通信.

3)实现
	创建一个顾客线程(消费者): 告知老板要的包子的种类和数量,调用wait方法,放弃CPU的执行,进入到WAITING状态(无限等待);

	创建一个老板线程(生产者): 花了5s做包子,做好包子之后,调用notify方法,唤醒顾客吃包子;

	注意:
		顾客和老板线程必须使用同步代码块包裹起来,保证等待和唤醒只能有一个在执行.
		同步使用的锁对象必须保证唯一.
		只有锁对象才能调用wait和notify方法.

4)Object的方法
	void wait(): 
	  在其它线程调用此对象和notify方法或notifyall方法前,导致当前线程等待.

	void notify(): 
	  唤醒在此对象监视器上等待的单个线程. 
	  会继续执行wait方法之后的代码.

	  有多个等待的线程的话,会随机唤醒一个;

	wait(long m): 
		在m毫秒结束后,还没有被notify唤醒,就会自动醒来;
		和sleep方法是一样的;

	void notifyAll():
		唤醒在此对象监视器上等待的所有线程;

		唤醒所有等待的线程;

5)等待唤醒机制(线程间通信):
	吃包子和做包子之间的协调: 
		不能吃的时候,还没做出来.
		不能做出来,没人吃.

6)通信: 对包子的状态进行判断
	没有包子-->吃货线程唤醒包子线程-->吃货线程等待-->包子铺线程做包子-->做好包子-->修改包子状态为有;
	有包子-->包子铺线程唤醒吃货线程-->包子铺线程等待-->吃货吃包子-->吃完包子-->修改包子的状态为没有;

	重点是利用好包子状态;

7) 任何对象都可以成为锁对象;

8)wait方法与notify方法必须要在同步代码块或者是同步函数中使用,因为:必须要通过锁对象调用这2个方法,保证了锁的唯一性;

9)分析:需要哪些类?(生产者消费者问题)
	1.资源类: 包子类
		设置包子的属性:
			皮
			馅
			包子的状态: 有true 没有false

	2.生产者(包子铺): 是一个线程类,可以继承Thread
		设置线程任务(run): 生成包子
		对包子的状态进行判断
		true: 有包子
			包子铺调用wait方法进入等待状态
		false: 没有包子
			增加一些趣味性,交替生产2种包子(i%2==0)
			包子铺线程生产好了包子
			修改包子的状态为true
			唤醒吃货线程,让吃货线程池包子

	3.消费者(吃货), 也是一个线程类,可以继承Thread
		设置线程任务(run): 吃包子
		对包子的状态进行判断
		false:没有包子
			吃货线程调用wait方法进入等待状态
		true:有包子
			吃货吃包子
			吃货吃完包子
			修改包子的状态为false没有
			吃货 唤醒 包子铺线程,生产包子

	4.测试类:
		包含main方法,程序执行的入口,启动程序;
		创建包子对象;
		创建包子铺线程,开启;
		创建吃货线程开启;

	注意: 
		包子铺线程和吃货线程的关系-->通信(互斥)
	    必须用同步技术保证2个线程只有一个在执行
		锁对象必须保证唯一,可以使用包子对象作为锁对象
		包子铺类和吃货类就需要把包子对象作为参数传递进去
			1.需要在成员位置创建一个包子变量
			2.使用带参数构造方法,为这个包子变量赋值

BaoZI.java // 包子

package com.itcast.thread07.demo01;

public class BaoZI {
    String pi;
    String xian;
    boolean flag = false; // 是否生产好了
}

BaoZiPu.java // 包子铺

package com.itcast.thread07.demo01;

public class BaoZiPu extends Thread {
    private BaoZI bz;

    public BaoZiPu(BaoZI bz) {
        this.bz = bz;
    }

    @Override
    public void run() {
        int count = 0;
        while (true) {
            synchronized (bz) {
                if (bz.flag == true) {
                    try {
                        bz.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                if (count % 2 == 0) {
                    bz.pi = "薄皮";
                    bz.xian = "三鲜";
                } else {
                    bz.pi = "冰皮";
                    bz.xian = "大葱";
                }

                count++;

                System.out.println("包子铺正在生产" + bz.pi + " " + bz.xian + " 包子");

                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                bz.flag = true;
                bz.notify();
                System.out.println("包子铺已经生产好了" + bz.pi + " " + bz.xian + " 包子,吃货可以开吃了");
            }
        }
    }
}

ChiHuo

package com.itcast.thread07.demo01;

public class ChiHuo extends Thread {
    private BaoZI bz;

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

    @Override
    public void run() {
        while (true) {
            synchronized (bz) {
                if (bz.flag == false) {
                    try {
                        bz.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                System.out.println("吃货正在吃" + bz.pi + " " + bz.xian + " 的包子");
                bz.flag = false;
                bz.notify();
                System.out.println("吃货把" + bz.pi + " " + bz.xian + " 的包子吃完了!\n");
            }
        }
    }
}

Demo

package com.itcast.thread07.demo01;

public class Demo {
    public static void main(String[] args) {
        BaoZI bz = new BaoZI();
        ChiHuo ch = new ChiHuo(bz);
        BaoZiPu bzp = new BaoZiPu(bz);

        ch.start();
        bzp.start();
    }
}

包子铺正在生产薄皮 三鲜 包子
包子铺已经生产好了薄皮 三鲜 包子,吃货可以开吃了
吃货正在吃薄皮 三鲜 的包子
吃货把薄皮 三鲜 的包子吃完了!

包子铺正在生产冰皮 大葱 包子
包子铺已经生产好了冰皮 大葱 包子,吃货可以开吃了
吃货正在吃冰皮 大葱 的包子
吃货把冰皮 大葱 的包子吃完了!

包子铺正在生产薄皮 三鲜 包子
包子铺已经生产好了薄皮 三鲜 包子,吃货可以开吃了
吃货正在吃薄皮 三鲜 的包子
吃货把薄皮 三鲜 的包子吃完了!

包子铺正在生产冰皮 大葱 包子
包子铺已经生产好了冰皮 大葱 包子,吃货可以开吃了
吃货正在吃冰皮 大葱 的包子
吃货把冰皮 大葱 的包子吃完了!

包子铺正在生产薄皮 三鲜 包子
包子铺已经生产好了薄皮 三鲜 包子,吃货可以开吃了
吃货正在吃薄皮 三鲜 的包子
吃货把薄皮 三鲜 的包子吃完了!

包子铺正在生产冰皮 大葱 包子
包子铺已经生产好了冰皮 大葱 包子,吃货可以开吃了
吃货正在吃冰皮 大葱 的包子
吃货把冰皮 大葱 的包子吃完了!

包子铺正在生产薄皮 三鲜 包子

Process finished with exit code -1

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值