生产者和消费者(三种方式)

第一种:生产者和消费者(使用synchronized 锁)

此方法的特点:因为synchronized 锁只能创建一个队列,因此在唤醒其他线程的时候必须要唤醒所有的线程,才能保证生产者和消费者交替运行。代码实现如下;

Bread类

package com.qf.gp2002_2;

/*
 * wgy
 * 2020/8/5
 * 11:30
 */
public class Bread {
    private int id;
    private String productName;

    public Bread(int id, String productName) {
        this.id = id;
        this.productName = productName;
    }

    public Bread() {
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getProductName() {
        return productName;
    }

    public void setProductName(String productName) {
        this.productName = productName;
    }

    @Override
    public String toString() {
        return "Bread{" +
                "id=" + id +
                ", productName='" + productName + '\'' +
                '}';
    }
}

BreadCon类

package com.qf.gp2002_2;

/*
 * wgy
 * 2020/8/5
 * 11:31
 */
public class BreadCon {
    //数组
    private Bread[] cons=new Bread[6];
    //元素个数
    private int size;
    //放入面包
    public synchronized void put(Bread b){
        while(size>5){
            //等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        cons[size]=b;
        System.out.println(Thread.currentThread().getName()+"生产了"+b.getId()+"号面包");
        size++;
        //唤醒消费者
        this.notifyAll();
    }
    //取走面包
    public synchronized void take(){
        while(size<=0){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        size--;
        Bread b=cons[size];
        cons[size]=null;
        System.out.println(Thread.currentThread().getName()+"消费了"+b.getId()+"号面包,生产者:"+b.getProductName());

        //唤醒生产者
        this.notifyAll();

    }



}

生产者(Produce类)

public class Produce implements Runnable{
    private BreadCon con;
    public Produce(BreadCon con){
        this.con=con;
    }

    @Override
    public void run() {
        for(int i=0;i<100;i++){
            con.put(new Bread(i, Thread.currentThread().getName()));
        }
    }
}

消费者(Consume类)

public class Consume implements Runnable {
    private BreadCon con;

    public Consume(BreadCon con) {
        this.con = con;
    }

    @Override
    public void run() {
        for(int i=0;i<100;i++){
            con.take();
        }
    }
}

测试类(TestBread类)

public class TestBread {
    public static void main(String[] args) {
        //面包容器
        BreadCon breadCon=new BreadCon();
        //创建生产和消费
        Produce produce=new Produce(breadCon);
        Consume consume=new Consume(breadCon);
        //创建线程对象
        Thread zhuxi=new Thread(produce, "铸玺");
        Thread bingbing=new Thread(consume,"冰冰");
        Thread zhuxi2=new Thread(produce, "铸玺2");
        Thread bingbing2=new Thread(consume,"冰冰2");
        //启动
        zhuxi.start();
        bingbing.start();
        zhuxi2.start();
        bingbing2.start();
    }
}

第二种:生产者和消费者(使用Lock锁中的Condition接口)

此方法的特点:因为Condition接口具有创建多队列的能力,因此可以将生产者和消费者分别放入不同的队列中,因此在唤醒线程的时候可以指定唤醒消费者或者是生产者,不用唤醒全部线程就能够实现生产者和消费者交替运行的效果。代码实现如下:

Bread类

public class Bread {
    private int id;
    private String prouductName;

    public Bread(int id, String prouductName) {
        this.id = id;
        this.prouductName = prouductName;
    }

    public Bread() {
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getProuductName() {
        return prouductName;
    }

    public void setProuductName(String prouductName) {
        this.prouductName = prouductName;
    }

    @Override
    public String toString() {
        return "Bread{" +
                "id=" + id +
                ", prouductName='" + prouductName + '\'' +
                '}';
    }
}

BreadCon类

public class BreadCon {
    //数组容器
    private Bread[] con=new Bread[6];
    //元素个数
    private int size;
    //创建Lock
    private Lock lock=new ReentrantLock();
    //创建条件队列
    //Condition condition=lock.newCondition();
    //创建多个条件队列
    //生产者队列
    private Condition proCondition=lock.newCondition();
    //消费者队列
    private Condition conCondition=lock.newCondition();

    //放入元素
    public  void put(Bread b){
        //上锁
        lock.lock();
        try {
            while (size > con.length-1) {
                try {
                    proCondition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(size+"-----------------"+ Thread.currentThread().getName());
            con[size] = b;
            size++;
            System.out.println(Thread.currentThread().getName() + "生产了" + b.getId() + "号面包");
            //唤醒所有
            conCondition.signal();
        }finally {
            //解锁
            lock.unlock();
        }

    }

    //取出面包
    public  void take(){
        //上锁
        lock.lock();
        try {
            while(size <= 0) {
                try {
                    conCondition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            size--;
            System.out.println(size+"-----------------"+ Thread.currentThread().getName());
            Bread b = con[size];
            con[size] = null;
            System.out.println(Thread.currentThread().getName() + "消费了" + b.getId() + "号面包,生产者:" + b.getProuductName());
            proCondition.signal();
        }finally {
            //解锁
            lock.unlock();
        }
    }

}

测试

public class TestBread {
    public static void main(String[] args) {
        //创建容器
        BreadCon con=new BreadCon();
        //生产对象
        Runnable produce=new Runnable() {
            @Override
            public void run() {
                for(int i=0;i<10;i++){
                    con.put(new Bread(i, Thread.currentThread().getName()));
                }
            }
        };
        //消费对象
        Runnable consume=new Runnable() {
            @Override
            public void run() {
                for(int i=0;i<10;i++){
                    con.take();
                }
            }
        };
        //创建线程对象
        Thread zhuxi=new Thread(produce, "铸玺");
        Thread bingbing=new Thread(consume, "冰冰");
        Thread zhuxi2=new Thread(produce, "铸玺2");
        Thread bingbing2=new Thread(consume, "冰冰2");
        //启动线程
        zhuxi.start();
        zhuxi2.start();
        bingbing.start();
        bingbing2.start();
    }
}

第三种:生产者和消费者(使用阻塞队列)

此方法的特点:不需要手动唤醒线程,当生产了一定数量后生产者队列就会自动进入等待队列中,等到消费者消费。消费线程也是一样。注意的是在运行的过程中可能会发生运行完生产者还没有及时打印,就别消费者抢走了导致控制台输出出现了问题,但是运行结果是正确的生产多少就消费多少。不会产生多消费或者多生产的情况。代码实现如下:

public class TestBlockingQueue {
    public static void main(String[] args) {
        //1创建阻塞队列
        ArrayBlockingQueue<String> queue=new ArrayBlockingQueue<>(6);
//        LinkedBlockingQueue queue=new LinkedBlockingQueue(6);
        //2创建线程
        Runnable produce=new Runnable() {
            @Override
            public void run() {
                for(int i=0;i<30;i++) {
                    try {
                        queue.put(Thread.currentThread().getName() + "---" + i);
                        System.out.println(Thread.currentThread().getName()+"生产了:"+i);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };

        Runnable consume=new Runnable() {
            @Override
            public void run() {
                for(int i=0;i<30;i++) {
                    try {
                        String take = (String)queue.take();
                        System.out.println(Thread.currentThread().getName()+"消费了:"+take);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        new Thread(produce,"铸玺").start();
        new Thread(consume,"冰冰").start();

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值