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

来源:互联网 发布:mac能装steam吗 编辑:程序博客网 时间:2024/05/16 13:46

生产者消费者模型(多个生产者和多个消费者)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 中更灵活、更具可伸缩性的锁定机制

0 0
原创粉丝点击