A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

    java基础加强学了多线程和等待唤醒机制,通过查阅API等资料,想实现多个生产者和多个消费者之间正确的通信,现以生产消费馒头为例,代码如下:
import java.util.ArrayList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ProduceComsumerNew {
    public static void main(String[] args) {
        Mantou mantou = new Mantou();
        new Thread(new Producer1(mantou,"红糖馒头"),"馒头铺1").start();
        new Thread(new Producer1(mantou,"韭菜馒头"),"馒头铺2").start();
        new Thread(new Producer1(mantou,"玉米馒头"),"馒头铺3").start();
        new Thread(new Consumer1(mantou),"AAA").start();
        new Thread(new Consumer1(mantou),"BBB").start();
        new Thread(new Consumer1(mantou),"CCC").start();
    }
}

//生产者
class Producer1 implements Runnable{
    private Mantou mantou;
    private String name;

    Producer1(Mantou mantou,String name) {
        this.mantou = mantou;
        this.name = name;
    }
    @Override
    public void run() {
        while (true) {
            //让线程争抢的能力下降
            Thread.currentThread().setPriority(4);
            mantou.produce(name);
            //让线程恢复争抢能力
            Thread.currentThread().setPriority(5);
        }
    }
}

//消费者
class Consumer1 implements Runnable {
    private Mantou mantou;

    Consumer1(Mantou mantou) {
        this.mantou = mantou;
    }

    @Override
    public void run() {
        while (true) {
            //让线程争抢的能力下降
            Thread.currentThread().setPriority(4);
            mantou.consume();
            //让线程恢复争抢能力
            Thread.currentThread().setPriority(5);
        }
    }
}

//产品
class Mantou {
    //馒头名称
    private String name;
    //记录数量
    private int count = 0;
    //最大生产量
    private int max = 5;
    //创建一个容器放馒头
    private ArrayList<Mantou> arrayList = new ArrayList<>(10);
    //创建一把锁控制同步
    private Lock lock = new ReentrantLock();
    //创建和锁绑定的Condition对象,控制生产者
    private Condition pro = lock.newCondition();
    //创建和锁绑定的Condition对象,控制消费者
    private Condition con = lock.newCondition();

    public Mantou() {
    }

    public Mantou(String name) {
        this.name = name;
    }

    //生产功能
    public void produce(String name) {
        lock.lock();
        try {

            //判断是否该生产
            if (count == max) {
                pro.await();
                //防止线程唤醒后直接从此处往下执行,未找到最终原因。****************
                pro.signal();
                return;
            }
            arrayList.add(new Mantou(name));
            System.out.println(Thread.currentThread().getName()+"生产了一个:"
                    +name+"包子,库存:"+(++count)+"个");

            con.signalAll();
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    //消费功能
    public void consume() {
        lock.lock();
        try {
            //判断是否可以消费
            if(count == 0) {
                con.await();
                //防止线程唤醒后直接从此处往下执行,未找到最终原因。****************
                con.signal();
                return;
            }
            Mantou m = arrayList.remove(0);
            System.out.println(Thread.currentThread().getName()+"消费了一个:"
                    +m.name+"还剩:"+(--count)+"个");

            pro.signalAll();
            Thread.sleep(500);

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}
最后打印结果为:
馒头铺2生产了一个:韭菜馒头包子,库存:1个
馒头铺2生产了一个:韭菜馒头包子,库存:2个
馒头铺1生产了一个:红糖馒头包子,库存:3个
馒头铺3生产了一个:玉米馒头包子,库存:4个
BBB消费了一个:韭菜馒头还剩:3个
BBB消费了一个:韭菜馒头还剩:2个
CCC消费了一个:红糖馒头还剩:1个
CCC消费了一个:玉米馒头还剩:0个
馒头铺2生产了一个:韭菜馒头包子,库存:1个
馒头铺2生产了一个:韭菜馒头包子,库存:2个
馒头铺2生产了一个:韭菜馒头包子,库存:3个
馒头铺2生产了一个:韭菜馒头包子,库存:4个
馒头铺1生产了一个:红糖馒头包子,库存:5个
BBB消费了一个:韭菜馒头还剩:4个
BBB消费了一个:韭菜馒头还剩:3个
AAA消费了一个:韭菜馒头还剩:2个
AAA消费了一个:韭菜馒头还剩:1个
AAA消费了一个:红糖馒头还剩:0个
。。。。。。

    虽然程序跑了一段时间未出现问题,但多线程的实现需要考虑很多细节,否则无法保证永久不出错。比如代码中******结尾的注释下的代码,如果不加这一段逻辑则会出现当前线程被唤醒后直接往下执行(跳过if判断)的情况,如果有同学知道真正的细节,还请指出,谢谢。

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马