生产者和消费者
核心思想:利用桌子来控制线程的执行。
消费者等待
消费者抢到了桌子的执行权,但是由于桌子上没有吃的,所以消费者需要先等待(wait)
消费者等待时,cpu的执行权一定会被厨师拿走,制作好食物后,唤醒消费者来吃饭。
生产者等待
厨师抢到了执行权后,但是桌子上已经有食物了,厨师会进行等待(wait)
cpu的执行权会被消费者拿走,吃完之后,唤醒厨师继续做饭。
常见方法
wait和notify方法注意事项
1、wait和notify方法必须同时由一个锁对象调用。这是因为notify唤醒的是使用同一个锁的对象调用wait方法的线程。
2、wait和notify方法都是属于Object类的方法。
锁对象可以是任何对象,而任意对象都是继承了Object类的。
3、wait和notify只能用在同步代码块或者同步方法中,这是因为只能通过锁对象调用这两个方法。
案例说明
//ThreadDemo
public class ThreadDemo {
public static void main(String[] args) {
//创建线程的对象
cook1 cook1=new cook1();
foodie1 foodie1=new foodie1();
//给线程设置名字
cook1.setName("厨师");
foodie1.setName("吃货");
//开启线程
cook1.start();
foodie1.start();
}
}
//desk
public class desk {
/*
作用:控制生产者和消费者的执行
*/
//
public static int foodFlag=0;//这里不是boolean类型是因为, 可能会有多条线程,为了通用性
//总个数
public static int count=10;
//锁对象
public static Object lock=new Object();
}
//foodie
public class foodie1 extends Thread{
/*
1、循环
2、同步代码块
3、判断共享数据是否到了末尾,是
4、判断共享数据是否到了末尾,否
*/
/*
桌子作为等待唤醒机制的中枢机构
*/
@Override
public void run() {
while(true){
synchronized (desk.lock){
if(desk.count==0){
break;
}else {
//判断桌子上有咩有面条
if(desk.foodFlag==0){
//如果没有就等待,
try {
desk.lock.wait();//让当前线程和锁绑定
} catch (InterruptedException e) {
e.printStackTrace();
}
}else{
//把吃的总数-1,
desk.count--;
//如果有就开吃
System.out.println("消费者在进食,还可以吃"+desk.count+"碗");
//吃完之后唤醒厨师继续做
desk.lock.notifyAll();
desk.foodFlag=0;
}
}
}
}
}
}
//cook
public class cook1 extends Thread{
@Override
public void run() {
/*
1、循环
2、同步代码块
3、判断共享数据是否已经达到末尾。是的
4、判断共享数据是否已经达到末尾。不是
*/
while(true){
synchronized (desk.lock){
if(desk.count==0){
break;//如果所有的食物都被吃完了,结束线程
}else{
//判断桌子上是否有食物
if(desk.foodFlag==1){
//如果有,等待
try {
desk.lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
//如果没有,就制作食物
System.out.println("厨师做了一碗面条");
//修改桌子上的食物状态
desk.foodFlag=1;
//叫醒等待的消费者开吃
desk.lock.notifyAll();
}
}
}
}
}
}