Java基础22 多线程之多生产者多消费者

一、单一生产者消费者

包子案例
多个类(称为线程一类,线程二类) 需要一个共有的变量,即将这个变量封装为一个类(称为属性类)的属性,注意属性类的属性修饰符为public公共的,在测试类中new 这个属性类实例化为对象,然后将此对象作为参数传入需要的多个类(线程一,线程二)中,就可以实现共享对象的属性即变量,且多个类(线程一,线程二) 需要定义此对象(属性类)为私有变量,并提供有参构造
生产者线程和消费者线程要有共享对象,即将包子提升为类作为参数传入生产者线程和消费者线程,这个包子类就是共享的对象,就可以使用 synchronized(包子类) 锁住共享对象包子,就不会发生多线程的通信问题,多个生产者和消费者也是这个原理只是共享对象变成队列而已
线程就是一个普通的类,可以随便写,只是继承Thread类,必须要重写run()方法,当然不重写runf方法就不是多线程了,起不到线程的作用。线程实现方式第一种方式是继承extends Thread 第二种是实现Implements Runnable 接口 第三种 是实现 Implements Callable接口,其中第二种方式 多线程自动共享数据 ,第三种方式带返回值 三种方式实现线程的子类都是普通的类,只是多了一个重写方法
代码
要点:生产者线程增加包子属性,有参构造方法。重写run方法里的线程的while的条件表达式,if(包子的状态存在) {需要等待} 包子不存在就生产包子,或做其他一系列要做的事,然后将包子状态改变,唤醒其他线程
消费者线程增加包子属性,有参构造方法。重写run方法里的线程的while的条件表达式,if(包子的状态不存在) {需要等待} 包子存在就消费包子,或做其他一系列要做的事,然后将包子状态改变,包子数量++(为什么只在消费者线程有着语句,因为生产一个包子再消费一个包子才算一轮)唤醒其他线程

看了后面,重写run方法里的线程的while的条件表达式(建议直接为true,后面再多写个if(条件){break}跳出循环)
包子类
要点:共享的数据类,可以写任何想要的数据

package day22;

public class BaoZi {
    public String pi;
    public String xian;
    //定义一个标记表示是否存在包子 false 没有包子 ture 有包子
    boolean flag = false;
    //boolean 默认值为false
    int count=1;
}

生产者类

package day22;

public class ProducterThread extends  Thread{
    private BaoZi baoZi;
    public  ProducterThread(BaoZi baoZi){
        this.baoZi = baoZi;
    }

    @Override
    public void run() {
        //一直生产包子
        while (baoZi.count<10){
            //同步代码块 //互斥锁
            synchronized(baoZi){
                //已存在包子 等待消费  不需要在生产
                if(baoZi.flag){
                    try {
                        baoZi.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //不存在包子 开始生产包子
                baoZi.pi = "薄皮";
                baoZi.xian ="韭菜鸡蛋";
                System.out.println("==============");
                //System.out.println("我生产了一个"+baoZi.pi+baoZi.xian+"的包子");
                System.out.println("我生产了第"+baoZi.count+"个"+baoZi.pi+baoZi.xian+"的包子");

                //将标记值设置为ture
                baoZi.flag = true;
                //通知消费者去消费
                baoZi.notify();
            }
        }
    }
}

消费者类

package day22;

public class CustomerThread extends Thread{
    private  BaoZi baoZi;
    public CustomerThread(BaoZi baoZi){
        this.baoZi=baoZi;
    }

    @Override
    public void run() {
        while (baoZi.count<=10){
            synchronized (baoZi){
                //如果包子不存在 等包子生成出来
                //可以将!baoZi.flag 换成 baoZi.flag == false 就好理解了
                if(!baoZi.flag){
                    //无线等待
                    try {
                        baoZi.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //包子存在 吃包子
                //System.out.println("我消费了一个"+baoZi.pi+baoZi.xian+"的包子");
                System.out.println("我消费了第"+baoZi.count+"个"+baoZi.pi+baoZi.xian+"的包子");
                baoZi.count++;
                baoZi.pi=null;
                baoZi.xian=null;
                //标记设置为false
                baoZi.flag = false;
                //通知生产者开始生产
                baoZi.notify();
            }
        }
    }
}

测试类

package day22;

public class Test05 {
    public static void main(String[] args) {
        BaoZi baoZi =new BaoZi();
        //开启生产者的线程
        new ProducterThread(baoZi).start();
        //开启消费者的线程
        new CustomerThread(baoZi).start();
    }
}

二、多生产者多消费者

原文地址

1.使用 Runnable 第二种方式实现多线程 一生产者多消费者

package threadsDemo;

import java.util.ArrayList;
import java.util.Random;


public class BreadShop {

    // 装包子的盘子
    public ArrayList<Bread> breadList = new ArrayList<Bread>();
    // 包子的种类:肉包和菜包
    public  BreadType [] breadTypes = { BreadType.MEAT, BreadType.VEGETABLES };
    // 已经出炉的包子总数
    public int totalCount = 0;
    // 点的包子数
    public final int MAX_COUNT = 20;
    enum BreadType{
        MEAT,VEGETABLES
    }
    class Bread {
        public BreadType type;
        public Bread(BreadType type){
            this.type=type;

        }

    }

    class Product implements Runnable {
        /*private boolean isWork = false;
        public Product() {
            this.isWork = true;
        }*/

        // 把包子蒸熟后放到盘子里
        public void makeBread(Bread bread) {
            breadList.add(bread);
            switch(bread.type)
            {
                case MEAT:
                    System.out.println("老板生产了一个肉包");
                    break;

                case VEGETABLES:
                    System.out.println("老板生产了一个菜包");
                    break;
                default:
                    break;
            }
        }

        @Override
        public void run() {
            while(true/*isWork*/)
            {
                try {
                    synchronized(breadList)
                    {
                        // 他们还没吃完,继续等待
                        if(breadList.size() > 0) {
                            breadList.wait();
                        }
                        // 一次蒸10个包子
                        for(int i = 0; i < 10; ++ i)
                        {
                            int type = new Random().nextInt(2);
                            Bread bread = new Bread(breadTypes[type]);
                            this.makeBread(bread);
                        }
                        totalCount += 10;
                        // 通知他们可以吃包子了
                        breadList.notifyAll();
                    }
                    // 做完了20个包子
                    if(totalCount >= MAX_COUNT)
                    {
                        //isWork = false;
                        break;
                    }
                }catch(Exception e) {
                    e.printStackTrace();
                    //isWork = false;
                }
            }

        }
    }


    class Consumer implements Runnable
    {

        private int id;
        public Consumer(int id)
        {
            this.id = id;
        }
        // 吃包子
        public void eat(Bread bread)
        {
            BreadType type = bread.type;
            switch (type) {
                case MEAT:
                    System.out.println(id + "号消费者" + "吃了一个肉包");
                    break;

                case VEGETABLES:
                    System.out.println(id + "号消费者" + "吃了一个菜包");
                    break;
                default:
                    break;
            }
        }
        @Override
        public void run() {
            while(true)
            {
                try{
                    synchronized(breadList)
                    {
                        // 包子还没做好
                        if(breadList.size() == 0)
                        {
                            // 吃完了所有包子
                            if(totalCount >= MAX_COUNT) {
                                break;
                            }
                            // 通知老板娘赶快做包子
                            breadList.notifyAll();
                            // 等老板娘做包子
                            breadList.wait();
                        }
                        else
                        {
                            // 从盘子里拿包子吃
                            Bread bread = breadList.remove(0);
                            this.eat(bread);

                        }
                    }
                    // 这里模拟吃包子的时间,也可以增大其他线程获得锁的概率,提高公平性
                    Thread.sleep(100);

                }catch(Exception e)
                {
                    e.printStackTrace();
                    //break;
                }
            }

        }
    }


    public static void main(String[] args) {
        BreadShop bs = new BreadShop();
        //内部类的实例化 先实例化外部类 再 内部类 对象名 = 外部类对象名.new 内部类
        //最原始的是 实例化静态内部类对象的模板是: 外部类类名.内部类类名 xxx = new 外部类类名.内部类类名()
        //实例化非静态内部类对象的模板是:外部类类名.内部类类名 xxx = 外部类对象名.new 内部类类名()
        //BreadShop.Consumer consumer =bs.new Consumer(1);
        // 5个coder来到包子店点包子
        for(int i = 1; i < 6; ++ i)
        {
            Thread t = new Thread(bs.new Consumer(i));
            t.start();
        }
        // 老板娘开始做包子
        Thread productThread = new Thread(bs.new Product());
        //productThread.setPriority(Thread.MAX_PRIORITY);
        productThread.start();
    }


}

内部类的实例化 先实例化外部类 再 内部类 对象名 = 外部类对象名.new 内部类
最原始的是
实例化静态内部类对象的模板是: 外部类类名.内部类类名 xxx = new 外部类类名.内部类类名()
实例化非静态内部类对象的模板是:外部类类名.内部类类名 xxx = 外部类对象名.new 内部类类名()
BreadShop.Consumer consumer =bs.new Consumer(1);

2.使用extends 第一种方式实现多线程 一生产者多消费者

共享数据类

package ThreadsDemo1;

import java.util.ArrayList;
import java.util.List;

public class BaoZiDate {
    public List<BaoZi> baoZiList = new ArrayList<>();
    public BaoZiType[] baoZiTypes = {BaoZiType.MEAT, BaoZiType.VEGETABLES, BaoZiType.XIAO};
    //最多包子数,只卖20个 ,一个集合10个,生产10个再卖
    public final int MAX_COUNT = 20;
    //已经卖了的包子数
    public int totalCount=0;

    enum BaoZiType {
        MEAT,VEGETABLES,XIAO;
    }
    class BaoZi {
        public BaoZiType baoZiType;

        public BaoZi(BaoZiType baoZiType) {
            this.baoZiType = baoZiType;
        }
    }

}

生产者类

package ThreadsDemo1;

import java.util.Random;

public class Product extends Thread{
    private BaoZiDate shareDate;

    public Product(BaoZiDate shareDate) {
        this.shareDate = shareDate;
    }

    @Override
    public void run() {
        while (true){

                synchronized (shareDate){
                    //包子集合有包子
                    if(shareDate.baoZiList.size()>0){
                        try {
                            shareDate.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    //包子集合没有包子,生产包子
                    for (int i = 0; i < 10; i++) {
                        int type =new Random().nextInt(3);
                        //作用等同于 int type = (int)(Math.random()*4); 但是Math.random()在多线程中不安全
                        BaoZiDate.BaoZi baoZi = shareDate.new BaoZi(shareDate.baoZiTypes[type]);
                        shareDate.baoZiList.add(baoZi);
                        switch(baoZi.baoZiType)
                        {
                            case MEAT:
                                System.out.println("老板生产了一个肉包");
                                break;

                            case VEGETABLES:
                                System.out.println("老板生产了一个菜包");
                                break;
                            case XIAO:
                                System.out.println("老板生产了一份小笼包");
                                break;
                            default:
                                break;
                        }
                    }
                    shareDate.totalCount += 10;

                    shareDate.notifyAll();

                }
                if(shareDate.totalCount>= shareDate.MAX_COUNT){
                   break;
                }

        }
    }
}

消费者类
通知生产者做包子
shareDate.notifyAll();
等生产者做包子
shareDate.wait();
因为条件是包子集合为0,没有包子在唤醒生产者,生产者就会生产10个包子,这样就会生产者生产10个包子后,消费者再吃这10个包子,吃完生产者在生产10个,有顺序的完成一轮,如果放在吃了一个包子后就唤醒,则会生产者生产10个包子,消费者1吃了一个包子,通知生产者再生产10个,然后19个包子由随机消费者消费
shareDate.notifyAll(); 换成 shareDate.notify(); 实测无区别,因为wait() 是 处于等待阻塞状态 且只有一个生产者在wait() 而另外四个消费者线程是可运行状态即就绪状态

package ThreadsDemo1;

public class Consumer extends Thread{
    private BaoZiDate shareDate;
    private int id;

    public Consumer(BaoZiDate shareDate, int id) {
        this.shareDate = shareDate;
        this.id = id;
    }

    @Override
    public void run() {
        while (true){

            try {
                synchronized (shareDate){
                    if(shareDate.baoZiList.size()==0){
                        if(shareDate.totalCount>= shareDate.MAX_COUNT){
                            break;
                        }
                        // 通知生产者做包子
                        shareDate.notifyAll();
                        // 等生产者做包子
                        shareDate.wait();

                    }
                    else {
                        //从包子集合里 获取包子吃
                        BaoZiDate.BaoZi baoZi = shareDate.baoZiList.remove(0);
                        switch(baoZi.baoZiType)
                        {
                            case MEAT:
                                System.out.println("消费者" + id + "吃了一个肉包");
                                break;

                            case VEGETABLES:
                                System.out.println("消费者" + id + "吃了一个菜包");
                                break;
                            case XIAO:
                                System.out.println("消费者" + id +"吃了一份小笼包");
                                break;
                            default:
                                break;
                        }

                    }
                }
                // 这里模拟吃包子的时间,也可以增大其他线程获得锁的概率,提高公平性
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }


        }

    }
}

测试类

package ThreadsDemo1;

public class Test {
    public static void main(String[] args) {
        BaoZiDate baoZiDate = new BaoZiDate();
        Thread th1 = new Product(baoZiDate);
        th1.start();
        for (int i = 0; i < 5; i++) {
            new Consumer(baoZiDate,i).start();
        }
    }
}

多生产者多消费者

虽然实现了多生产者多消费者,但是没有实现 多生产者先生产10个,在多消费者吃10个,吃完再通知多生产者生产10个的 顺序
共享数据类和消费者类 同上面一样
消费者

package ThreadsDemo1;

import java.util.Random;

public class Products extends Thread{
    private BaoZiDate shareDate;
    private int id;

    public Products(BaoZiDate shareDate,int id) {
        this.shareDate = shareDate;
        this.id=id;
    }

    @Override
    public void run() {
        while (true){

            synchronized (shareDate){
                //包子集合有包子
                if(shareDate.baoZiList.size()==10){
                    shareDate.notifyAll();
                    try {
                        shareDate.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }



                }
                //包子集合没满,继续生产包子
                int type = new Random().nextInt(3);
                //作用等同于 int type = (int)(Math.random()*4); 但是Math.random()在多线程中不安全
                BaoZiDate.BaoZi baoZi = shareDate.new BaoZi(shareDate.baoZiTypes[type]);
                shareDate.baoZiList.add(baoZi);
                switch (baoZi.baoZiType) {
                    case MEAT:
                        System.out.println(id + "号生产者生产了一个肉包");
                        break;

                    case VEGETABLES:
                        System.out.println(id + "号生产者生产了一个菜包");
                        break;
                    case XIAO:
                        System.out.println(id + "号生产者生产了一份小笼包");
                        break;
                    default:
                        break;
                }

                shareDate.totalCount++;
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }


                //shareDate.notifyAll();
                //shareDate.notify();

            }
            if(shareDate.totalCount>= shareDate.MAX_COUNT){
                break;
            }

        }
    }
}

测试类

package ThreadsDemo1;

public class Test02 {
    public static void main(String[] args) {
        BaoZiDate baoZiDate = new BaoZiDate();
        for (int i = 0; i < 3; i++) {
            new Products(baoZiDate,i).start();
        }
        for (int i = 0; i < 3; i++) {
            new Consumer(baoZiDate,i).start();
        }
    }


}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值