以前咱们在“Java并发编程初级篇(十二):使用wait和notify生产者消费者问题”,已经使用Java提供的synchronized关键字和wait(),notify(),notifyAll()方法实现过来生产者消费者问题。Java API还为咱们提供了锁的解决方案。java
使用锁解决阻塞要用到Condition,它是经过Lock.newCondition()来得到的。就像wait()和notify()必须在synchronized块内同样,Condition.await()和Condition.singialAll()方法也必须在Lock.lock()和Lock.unlock()内执行。编程
代码示例:并发
首先咱们实现一个数据缓冲区,缓冲区中定义了maxSize变量来表明缓冲区大小,LinkedList来模拟缓冲区。而后添加一把锁,并用这把锁来新建两个Condition:producer(控制生产者挂起和唤醒)和consumer(控制消费者挂起和唤醒)。当生产者发现缓冲区满的状况下调用producer.await()挂起,等待消费者消费数据后调用producer.singialAll()方法来唤醒,并从新判断缓冲区状态。当消费者发现缓冲区空的状况下调用consumer.await()挂起,等待生产者向缓冲区中放入数据并调用consumer.singialAll()方法唤醒并从新判断缓冲区状态。ide
public class DataBuffer { private int maxSize; private LinkedList<Date> buffer; private Lock lock; private Condition producer; private Condition consumer; public DataBuffer(int maxSize) { this.maxSize = maxSize; buffer = new LinkedList<Date>(); lock = new ReentrantLock(); producer = lock.newCondition(); consumer = lock.newCondition(); } public void put() { try { lock.lock(); while (buffer.size() == this.maxSize) { producer.await(); } buffer.add(new Date()); System.out.printf("%s: Add one %s. Buffer size is %d.\n", Thread.currentThread().getName(), buffer.peekLast(), buffer.size()); consumer.signalAll(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void get() { try { lock.lock(); while (buffer.size() == 0) { consumer.await(); } System.out.printf("%s: Get one %s. Buffer size is %d.\n", Thread.currentThread().getName(), buffer.pollFirst(), buffer.size()); producer.signalAll(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } }
建立两个线程用于模拟生产者和消费者this
public class Producer implements Runnable { private DataBuffer buffer; public Producer(DataBuffer buffer) { this.buffer = buffer; } @Override public void run() { buffer.put(); } } public class Consumer implements Runnable { private DataBuffer buffer; public Consumer(DataBuffer buffer) { this.buffer = buffer; } @Override public void run() { buffer.get(); } }
建立两个任务类线程启动10个生产者和消费者,生产者生产速度>消费者消费速度。.net
public class ProducerTask implements Runnable { private DataBuffer buffer; public ProducerTask(DataBuffer buffer) { this.buffer = buffer; } @Override public void run() { for (int i = 0; i < 10; i++) { new Thread(new Producer(buffer), "Producer-" + i).start(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
public class ConsumerTask implements Runnable { private DataBuffer buffer; public ConsumerTask(DataBuffer buffer) { this.buffer = buffer; } @Override public void run() { for (int i = 0; i < 10; i++) { new Thread(new Consumer(buffer), "Consumer-" + i).start(); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
主方法类中启动两个任务类线程,模拟生产者和消费者,由于生产者速度快,最终会致使生产者处于阻塞状态。线程
public class Main { public static void main(String[] args) { DataBuffer buffer = new DataBuffer(5); new Thread(new ProducerTask(buffer), "ProducerTask").start(); new Thread(new ConsumerTask(buffer), "ConsumerTask").start(); } }
日志,由于缓冲区大小为5,因此当缓冲区内容达到5个以后,生产者进入阻塞状态,并等待消费者消费数据后被唤醒并向缓冲区中插入数据。日志
Producer-0: Add one Fri Nov 25 15:36:21 CST 2016. Buffer size is 1. Consumer-0: Get one Fri Nov 25 15:36:21 CST 2016. Buffer size is 0. Producer-1: Add one Fri Nov 25 15:36:22 CST 2016. Buffer size is 1. Producer-2: Add one Fri Nov 25 15:36:23 CST 2016. Buffer size is 2. Producer-3: Add one Fri Nov 25 15:36:24 CST 2016. Buffer size is 3. Producer-4: Add one Fri Nov 25 15:36:25 CST 2016. Buffer size is 4. Consumer-1: Get one Fri Nov 25 15:36:22 CST 2016. Buffer size is 3. Producer-5: Add one Fri Nov 25 15:36:26 CST 2016. Buffer size is 4. Producer-6: Add one Fri Nov 25 15:36:27 CST 2016. Buffer size is 5. Consumer-2: Get one Fri Nov 25 15:36:23 CST 2016. Buffer size is 4. Producer-7: Add one Fri Nov 25 15:36:31 CST 2016. Buffer size is 5. Consumer-3: Get one Fri Nov 25 15:36:24 CST 2016. Buffer size is 4. Producer-8: Add one Fri Nov 25 15:36:36 CST 2016. Buffer size is 5. Consumer-4: Get one Fri Nov 25 15:36:25 CST 2016. Buffer size is 4. Producer-9: Add one Fri Nov 25 15:36:41 CST 2016. Buffer size is 5. Consumer-5: Get one Fri Nov 25 15:36:26 CST 2016. Buffer size is 4. Consumer-6: Get one Fri Nov 25 15:36:27 CST 2016. Buffer size is 3. Consumer-7: Get one Fri Nov 25 15:36:31 CST 2016. Buffer size is 2. Consumer-8: Get one Fri Nov 25 15:36:36 CST 2016. Buffer size is 1. Consumer-9: Get one Fri Nov 25 15:36:41 CST 2016. Buffer size is 0.