生产者和消费者是一个非常经典的多线程协作的模式

第一种:消费者等待

1、消费者先看有没有需要执行的代码,如果没有就等待

2、等待的过程中,生产者就会去生产代码

3、生产完代码后,就会唤醒消费者执行代码

第二种:生产者等待

1、生产者判断是否有代码,如果有就等待

2、等待的过程中,消费者就会去执行代码

3、生产者判断如果没有代码,就会去生产

4、生产完成后就会去唤醒消费者执行代码

完成生产者和消费者(等待唤醒机制)的代码:实现线程轮流交替执行的效果

package Day15_thread;

public class Cook extends Thread {
    @Override
    public void run() {
        //1、循环
        //2、同步代码块
        //3、判断共享数据是否到了末尾
        //4、判断共享数据是否到了末尾,没有到末尾
        while(true){
            synchronized (Desk.lock){
                //判断共享数据是否到了末尾
                if(Desk.count==0){
                    break;
                }else {
                    //1、判断桌子上是否有食物,如果有就等待
                    //2、如果没有食物,就生产
                    //3、生产完之后,就要修改桌子上食物的状态
                    //4、唤醒消费者
                    if(Desk.FoodFlag==1){
                        try {
                            Desk.lock.wait();//同样需要锁对象来调用wait,目的是绑定锁对象和线程
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }else {
                        //开始制作食物
                        System.out.println("生产者开始制作食物");
                        Desk.FoodFlag=1;
                        //唤醒消费者开吃
                        Desk.lock.notifyAll();
                    }
                }
            }
        }
    }
}

package Day15_thread;

public class Foodie extends Thread {
    @Override
    public void run() {
        //1、循环
        //2、同步代码块
        //3、判断共享数据是否到了末尾
        //4、判断共享数据是否到了末尾,没有到末尾
        while(true){
            synchronized (Desk.lock){
                if(Desk.count==0){
                    break;
                }else {
                    //先判断桌子上是否有实物
                    //如果没有就等待
                    //如果有就开吃
                    //吃完需要,唤醒生产者,还需要把吃的总数减一
                    //吃完之后需要修改桌子上食物FoodFlag的状态
                    if(Desk.FoodFlag==0){
                        //如果没有就等待,要用锁对象去调用wait方法
                        try {
                            Desk.lock.wait();//让当前进程和锁进行绑定
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }else {
                        //把吃的总数减一
                        Desk.count--;
                        //如果有就开吃
                        System.out.println("吃货在吃面条,还能吃"+Desk.count+"碗");
                        //吃完之后就要唤醒生产者
                        Desk.lock.notifyAll();
                        //修改桌子的状态
                        Desk.FoodFlag=0;
                    }
                }
            }

        }
    }
}

package Day15_thread;

public class Desk {
    //控制生产者cook和消费者Foodis的执行
    //用来描述是否有食物可以消费的一个标识
    //0:没有食物,1:有食物
    public static int FoodFlag=0;
    //总个数:标识消费者最多能消费的最大数量
    public static int count=10;
    //锁对象
    public static Object lock=new Object();

}
package Day15_thread;

public class ThreadTest01 {
    public static void main(String[] args) {
        Cook cook = new Cook();
        Foodie foodie = new Foodie();
        //给线程设置名字
        cook.setName("生产者");
        foodie.setName("消费者");
        //开启线程
        cook.start();
        foodie.start();

    }
}

等待唤醒机制的第二种实现方式:阻塞队列的方式实现

package Day15_thread;

import java.util.concurrent.ArrayBlockingQueue;

public class CookBlock extends Thread {

    ArrayBlockingQueue<String> queue;
    public CookBlock(ArrayBlockingQueue<String> queue) {
        this.queue = queue;
    }
    @Override
    public void run() {
        while (true) {
            //不断的把食物放到阻塞队列中
            try {
                queue.put("食物");
                System.out.println("生产者生产了食物");
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

    }
}

package Day15_thread;

import java.util.concurrent.ArrayBlockingQueue;

public class FoodieBlock extends Thread {

    ArrayBlockingQueue<String> queue;
    public FoodieBlock(ArrayBlockingQueue<String> queue) {
        this.queue = queue;
    }
    @Override
    public void run() {
        while (true) {
            //不断的从阻塞队列中获取食物
            try {
                String take = queue.take();
                System.out.println("消费者消费了"+take);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

    }
}
package Day15_thread;

import java.util.concurrent.ArrayBlockingQueue;

public class ThreadTest02 {
    public static void main(String[] args) {
        //利用阻塞队列来完成生产者和消费者的代码
        //细节:生产者和消费者必须使用同一个阻塞队列
        //1、在测试类创建阻塞队列的对象
        ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<String>(1);
        CookBlock cookBlock = new CookBlock(queue);
        FoodieBlock FoodieBlock = new FoodieBlock(queue);

        cookBlock.start();
        FoodieBlock.start();

    }
}

这个打印内容看似有问题,实际上,是因为输出语句放在了锁外面导致的,不影响实际共享数据

线程的状态:

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐