生产者消费者模型(多个生产者和多个消费者)JDK1.5 (Lock&Condition)实现版

本文介绍了一个使用JDK1.5的Lock和Condition实现的多生产者多消费者模型案例。通过共享资源的同步机制,确保了线程间的正确交互。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

生产者消费者模型(多个生产者和多个消费者)JDK1.5 (Lock&Condition)实现版

场景描述

多线程开发中很经典的一个案例就是生产者消费者模型,它们共享资源,但是对资源的操作方式并不同。因此它们需要协调资源,否则就会出现线程安全问题。尤其当时多个生产者和多个消费者时比较麻烦。本文以JDK1.5并发工具包下的Lock和Condition来实现多生产者多消费者模型。


代码展示

Resource Code

/**
* 生产者和消费者共享的资源Resource对象
* @author xuyi3
* @2016年4月7日 @下午2:01:21
* @Resource
* @功能说明:<br>
* @春风十里不如你
* @备注:使用Lock 和 Condition实现多生产者和多消费者模型
*/
public class Resource {

    /** 资源名称 */
    private String name;
    /** 资源标识符 */
    private boolean flag = false;
    // 区分产品的计数器
    private int count = 0;

    // 定义一个锁
    Lock lock = new ReentrantLock();
    // 生产者的监视器
    Condition conditionProduce = lock.newCondition();
    // 消费者的监视器
    Condition conditionConsumer = lock.newCondition();
    /**
     * 生产产品方法
     * @param threadName
     */
    public void produce(String threadName) {

        try {
            // 其实用tryLock方法更严谨些
            lock.lock();
            while (isFlag()) {// 如果已经存在数据,生产者就等待消费者消费之后再生产。注意多生产者时这里要使用while循环判断。
                // 线程等待
                conditionProduce.await();
            }
            setName("产品" + (++count));
            System.out.println(threadName + "生产者生产--->" + getName());
            setFlag(true);

            conditionConsumer.signal();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // finally代码块通常都是存放资源释放操作的代码
            // 不管执行过程发生什么情况都要释放锁资源,否则就会无限期等待下去了。导致程序崩溃
            lock.unlock();
        }

    }

    /**
     * 消费产品方法
     * @param threadName
     */
    public void consumer(String threadName) {

        try {
            // 其实用tryLock方法更严谨些
            lock.lock();
            while (!isFlag()) {// 如果没有数据消费者就等待生产者生产之后再消费,多消费者时这里要使用while循环判断。
                conditionConsumer.await();
            }
            System.out.println(threadName + "消费者消费=====》" + getName());
            setFlag(false);// 标识已经消费了
            conditionProduce.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // finally代码块通常都是存放资源释放操作的代码
            // 不管执行过程发生什么情况都要释放锁资源,否则就会无限期等待下去了。导致程序崩溃
            lock.unlock();
        }
    }
}

ProductThread Code

/**
* 生产者对象
* @author xuyi3
* @2016年4月7日 @下午1:38:16
* @ProductThread
* @功能说明:生产产品<br>
* @春风十里不如你
* @备注
*/
public class ProductThread implements Runnable {
    // 共享资源对象
    private Resource resource;
    public ProductThread(Resource resource) {
        this.resource = resource;
    }
    @Override
    public void run() {
        // 备注:比较优雅的多线程代码,在run()方法体内尽量出现较少的代码,不推荐把同步代码和一些复杂的逻辑放在run()方法体内。
        // 因为如果把所有同步代码都放在run()方法体内写的话,非常不好的维护并且代码结构不够清晰。
        while (true) {
            // 生产者生产产品
            resource.produce(Thread.currentThread().getName());
        }
    }
}

ConsumerThread Code

/**
* 消费者对象
* @author xuyi3
* @2016年4月7日 @下午2:07:22
* @ConsumerThread
* @功能说明:<br>
* @春风十里不如你
* @备注
*/
public class ConsumerThread implements Runnable {
    // 共享资源Resource对象
    private Resource resource;
    public ConsumerThread(Resource resource) {
        this.resource = resource;
    }
    @Override
    public void run() {
        // 备注:比较优雅的多线程代码,在run()方法体内尽量出现较少的代码,不推荐把同步代码和一些复杂的逻辑放在run()方法体内。
        // 因为如果把所有同步代码都放在run()方法体内写的话,非常不好的维护并且代码结构不够清晰。
        while (true) {
            // 消费者消费产品
            resource.consumer(Thread.currentThread().getName());
        }
    }
}

AppMain Code

public class AppMain {
public static void main(String[] args) {
        // 共享资源对象
        Resource resource = new Resource();
        // 创建生产者对象
        ProductThread productThread = new ProductThread(resource);
        // 创建消费者对象
        ConsumerThread consumerThread = new ConsumerThread(resource);

        // 启动两个线程
        new Thread(productThread, "生产者1 ").start();
        new Thread(consumerThread, "Consumer1").start();
        new Thread(productThread, "生产者2 ").start();
        new Thread(consumerThread, "Consumer2").start();
    }
}

总结说明

多个生产者和多个消费者模型实现的关键在于,资源共享(同步同个对象锁)和资源的标识以及等待唤醒机制wait()和notifyAll()方法。但是每次都需要要判断标识符,因此需要使用while而不能试if。JDK1.5之前使用这种方式处理还不错,但是这里有个明显的问题就是,每次都是唤醒所有的线程,并不是只唤醒我们希望唤醒的线程。这是会降低效率的,尤其是在线程数比较多并发量比较高的时候,就会显得性能并不高。本章使用JDK1.5之后的并发包下的Lock和Condition来高效解决这个问题,关于Lock和Condition的介绍可以参考java doc或Java 理论与实践: JDK 5.0 中更灵活、更具可伸缩性的锁定机制

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值