下面是一个经典的生产者消费者的例子。假设使用缓冲区存储整数,缓冲区的大小是受限制的。缓冲区提供write(int)方法将一个整数添加到缓冲区,还体统read()方法从缓冲区中读取并删除一个整数。为了同步操作,使用具有两个条件的锁,notEmpty(缓冲区非空)和notFull(缓冲区未满)。当任务相缓冲区添加爱一个int时,如果缓冲区是满的,那么任务将等待notFull状态,当任务从缓冲区总删除一个int时,如果缓冲区是空的,那么任务将等待notEmpty状态。
package LianXi; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.locks.*; public class ConsumerProducer{ private static Buffer _buffer = new Buffer(); public static void main(String[] args) { ExecutorService executor = Executors.newCachedThreadPool(); executor.execute(new ConsumerTask()); executor.execute(new ProducerTask()); } public static class ConsumerTask implements Runnable{ @Override public void run(){ while(true) _buffer.read(); } } public static class ProducerTask implements Runnable{ @Override public void run(){ while(true) _buffer.write((int)(Math.random()*1000000)); } } public static class Buffer{ private static final int CAPACITY=10; private LinkedList<Integer> _queue = new LinkedList<Integer>(); private static Lock _lock = new ReentrantLock(); private static Condition notEmpty = _lock.newCondition(); //不为空条件 private static Condition notFull = _lock.newCondition(); //未满条件 //返回Buffer的整数个数 public int getSize(){ return _queue.size(); } //是否为空 public boolean isEmpty(){ return _queue.isEmpty(); } //是否满了 public boolean isFull(){ return getSize()>=CAPACITY; } //添加一个整数到缓冲区 public void write(int integer){ _lock.lock(); try{ while(isFull()){ System.out.println("\n缓冲区已满,等待读取任务\n"); notFull.await(); } _queue.push(integer); System.out.println("\n想缓冲区中添加了"+integer); notEmpty.signalAll(); Thread.sleep(500); } catch(InterruptedException ex) { ex.printStackTrace(); } finally { _lock.unlock(); } } //读取并删除 public int read(){ int result = 0; _lock.lock(); try{ while( isEmpty( ) ){ System.out.println("\n缓冲区以为空,等待写入任务\n"); notEmpty.await(); } result = _queue.remove(); notFull.signalAll(); Thread.sleep(500); System.out.println("\n从缓冲区中读取了"+result); } catch(InterruptedException ex) { ex.printStackTrace(); } finally { _lock.unlock(); return result; } } } }
阻塞列队
阻塞列队在试图想一个满列队添加元素或这从空列队删除元素时会导致线程阻塞。BlockQueue接口扩展java.util.queue,并且提供同步的put和take方法想列队头部添加元素,以及从列队尾删除元素。
java支持三个具体的阻塞列队ArrayBlockingQueue、LinkedblockingQueue 和 PriorityBlockingQueue ,他们都在java。util.concurrent抱中。ArrayBlockingQueue使用数组实现阻塞列队,必须指定一个容量可选的公平性锁来构造ArrayBlocking。LinkedBlockingQueue使用链表来实现阻塞列队。可以创建不受限制或受限制的LinkedBlockingQueue。PriorityBlockingQueue 是优先列队,可以创建不受限或这受限的优先列队。对于不受限的LinkedBlockingQueue和PriorityBlockingQueue而言,put方法将永远不会阻塞线程。
可以使用阻塞列队替换生产者,消费者中的Buffer 来精简生产者和消费者模式。