前面阐述了实现生产者与消费者问题的一种方式:wait() / notify()方法,本文继续阐述多线程的经典问题---生产者与消费者的第二种方式:await() / signal()方法。
await() / signal()方法
在JDK5.0之后,Java提供了更加健壮的线程处理机制,包括同步、锁定、线程池等,它们可以实现更细粒度的线程控制。await()和signal()就是其中用来做同步的两种方法,它们的功能基本上和wait() / nofity()相同,完全可以取代它们,但是它们和新引入的锁定机制Lock直接挂钩,具有更大的灵活性。通过在Lock对象上调用newCondition()方法,将条件变量和一个锁对象进行绑定,进而控制并发程序访问竞争资源的安全。
缓冲区(仓库):
import java.util.LinkedList; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Storage { // 仓库最大存储量 private final int MAX_SIZE = 100; // 仓库存储的载体 private LinkedList<Object> list = new LinkedList<Object>(); // 锁 private final Lock lock = new ReentrantLock(); // 仓库满的条件变量 private final Condition full = lock.newCondition(); // 仓库空的条件变量 private final Condition empty = lock.newCondition(); // 生产num个产品 public void produce(int num){ // 获得锁 lock.lock(); // 如果仓库剩余容量不足 while (list.size() + num > MAX_SIZE){ System.out.println("【要生产的产品数量】:" + num + "【库存量】:" + list.size()+ "暂时不能执行生产任务!"); try{ // 由于条件不满足,生产阻塞 full.await(); } catch (InterruptedException e){ e.printStackTrace(); } } // 生产条件满足情况下,生产num个产品 for (int i = 1; i <= num; ++i){ list.add(new Object()); } System.out.println("【已经生产产品数】:" + num + "/t【现仓储量为】:" + list.size()); // 唤醒其他所有线程 full.signalAll(); empty.signalAll(); // 释放锁 lock.unlock(); } // 消费num个产品 public void consume(int num) { // 获得锁 lock.lock(); // 如果仓库存储量不足 while (list.size() < num){ System.out.println("【要消费的产品数量】:" + num + "【库存量】:" + list.size()+ "暂时不能执行生产任务!"); try{ // 由于条件不满足,消费阻塞 empty.await(); } catch (InterruptedException e){ e.printStackTrace(); } } // 消费条件满足情况下,消费num个产品 for (int i = 1; i <= num; ++i){ list.remove(); } System.out.println("【已经消费产品数】:" + num + "【现仓储量为】:" + list.size()); // 唤醒其他所有线程 full.signalAll(); empty.signalAll(); // 释放锁 lock.unlock(); } // set/get方法 public int getMAX_SIZE() { return MAX_SIZE; } public LinkedList<Object> getList() { return list; } public void setList(LinkedList<Object> list) { this.list = list; } }
生产者:
public class Producer extends Thread { // 每次生产的产品数量 private int num; // 所在放置的仓库 private Storage storage; // 构造函数,设置仓库 public Producer(Storage storage){ this.storage = storage; } // 线程run函数 public void run(){ produce(num); } // 调用仓库Storage的生产函数 public void produce(int num){ storage.produce(num); } // get/set方法 public int getNum() { return num; } public void setNum(int num) { this.num = num; } public Storage getStorage() { return storage; } public void setStorage(Storage storage) { this.storage = storage; } }
消费者:
public class Consumer extends Thread { // 每次消费的产品数量 private int num; // 所在放置的仓库 private Storage storage; // 构造函数,设置仓库 public Consumer(Storage storage){ this.storage = storage; } // 线程run函数 public void run(){ consume(num); } // 调用仓库Storage的生产函数 public void consume(int num){ storage.consume(num); } // get/set方法 public int getNum() { return num; } public void setNum(int num) { this.num = num; } public Storage getStorage() { return storage; } public void setStorage(Storage storage) { this.storage = storage; } }
测试类:
public class Test { public static void main(String[] args) { // 仓库对象 Storage storage = new Storage(); // 生产者对象 Producer p1 = new Producer(storage); Producer p2 = new Producer(storage); Producer p3 = new Producer(storage); Producer p4 = new Producer(storage); Producer p5 = new Producer(storage); Producer p6 = new Producer(storage); Producer p7 = new Producer(storage); // 消费者对象 Consumer c1 = new Consumer(storage); Consumer c2 = new Consumer(storage); Consumer c3 = new Consumer(storage); // 设置生产者产品生产数量 p1.setNum(10); p2.setNum(10); p3.setNum(10); p4.setNum(10); p5.setNum(10); p6.setNum(10); p7.setNum(80); // 设置消费者产品消费数量 c1.setNum(50); c2.setNum(20); c3.setNum(30); // 线程开始执行 c1.start(); c2.start(); c3.start(); p1.start(); p2.start(); p3.start(); p4.start(); p5.start(); p6.start(); p7.start(); } }