首页 > 代码库 > 生产者消费者模式的java实现(实现二)

生产者消费者模式的java实现(实现二)

这次采用ReentrantLock 实现生产者消费者模式,先说下ReentrantLock,通常叫做重入锁,所谓重入就是一个线程可以再次进入已经持有锁的代码块,在内部会对重入的次数进行计数,当计数为0,则释放锁。其实synchronized关键字所代表的内置锁,也是可以重入的。但是又有几点不同:

1、ReentrantLock将加锁与解锁进行分离,可以提供更细粒度的加解锁操作,内置锁基本都是全局锁(类,对象,代码块)

2、ReentrantLock提供了定时的加锁操作,这是内置锁无法做到的。

3、ReentrantLock提供了可轮询的加锁操作,即tryLock()方法,在循环中使用,可以减少线程争抢,减少系统调用和上下文切换,节省资源,这也是内置锁无法做到的。

 

package com.smikevon.concurrent;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class ProducerConsumer_05 {    public static void main(String[] args) {        final Drop drop = new Drop();        new Thread(new Runnable() {            public void run() {                try {                    new Producer(drop).produce();                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        },"生产者").start();        new Thread(new Runnable() {            public void run() {                try {                    new Consumer(drop).consume();                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        },"消费者").start();    }    static class Producer{        private Drop drop;        public Producer(Drop drop) {            this.drop = drop;        }        public void produce() throws InterruptedException{            String[] messages = {                    "我是",                    "一名程序员",                    "我很骄傲",                    "也很自豪",                    "爱岗敬业",                    "勤劳奉献",                    "无怨无悔",                    "奉献青春",                    "希望通过学习",                    "提升",                    "自己",                    "done",                };            for(int i=0;i<messages.length;i++){                drop.put(messages[i]);            }        }    }    static class Consumer{        private Drop drop;        public Consumer(Drop drop) {            this.drop = drop;        }        public void consume() throws InterruptedException{            String message = "";            do{                message = drop.take();            }while(!message.equals("done"));        }    }    static class Drop{        private Lock lock = new ReentrantLock();        //初始化条件为空        private Condition empty = lock.newCondition();        //条件为满,这里有一个就是满了        private Condition full = lock.newCondition();        private String message;        private boolean isExist = false ;        public void put(String message) throws InterruptedException{            while(true){                try{                    lock.lock();                    if(isExist){                        full.await();                    }                    this.message = message;                    isExist = true;                    empty.signal();                    System.out.println(Thread.currentThread().getName()+":"+message);                    break;                }finally{                    lock.unlock();                }            }        }        public String take() throws InterruptedException{            while(true){                try{                    lock.lock();                    if(!isExist){                        empty.await();                    }                    System.out.println(Thread.currentThread().getName()+":"+message);                    isExist = false;                    full.signal();                    return this.message;                }finally{                    lock.unlock();                }            }        }    }}

 

  这里使用了两个condition,一个表示是否满,一个表示是否空,赋予实际意义,如果有N个线程,定义N个condition条件。这样,在调用signal() 方法时,就是明确告诉该哪个线程从waiting状态中苏醒,恢复runnable状态。减少了内置锁notifyAll()带来的线程争抢锁,争抢时带来的系统调用和上线文切换非常消耗系统资源。

  第一篇和第二篇都是采用原始的锁工具实现生产者消费者模式,实际上java.util.concurrent包提供了一些方便的并发工具,这些工具能够非常方便的实现生产者消费者模式。例如Exchanger,semaphore等。

生产者消费者模式的java实现(实现二)