# 代码:
public class App { public static void main(String[] args) { Depot depot = new Depot(100); Producer producer = new Producer(depot); Consumer consumer = new Consumer(depot); producer.produce(60); consumer.consume(100); producer.produce(90); consumer.consume(40); } } class Producer { private Depot depot; public Producer(Depot depot) { this.depot = depot; } public void produce(final int val) { new Thread() { public void run() { depot.produce(val); } }.start(); } } class Consumer { private Depot depot; public Consumer(Depot depot) { this.depot = depot; } public void consume(final int val) { new Thread() { public void run() { depot.consume(val); } }.start(); } } class Depot { private int capacity; private int size; private Lock lock; private Condition fullCondition; private Condition emptyCondition; public Depot(int capacity) { this.size = 0; this.capacity = capacity; this.lock = new ReentrantLock(); fullCondition = lock.newCondition(); emptyCondition = lock.newCondition(); } public void produce(int val) { lock.lock(); try { int surplus = val; while (surplus > 0) { while (size >= capacity) { fullCondition.await(); } int incre = (size + surplus) > capacity ? (capacity - size) : surplus; size += incre; surplus -= incre; System.out.printf("%s plan to produce (%d), actually produce (%d), depot size (%d) ", Thread.currentThread().getName(), val, incre, size); emptyCondition.signal(); } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void consume(int val) { lock.lock(); try { int surplus = val; while (surplus > 0) { while (size <= 0) { emptyCondition.await(); } int desc = (size < surplus) ? size : surplus; size -= desc; surplus -= desc; System.out.printf("%s plan to consume (%d), actutally consume (%d), depot size (%d) ", Thread.currentThread().getName(), val, desc, size); fullCondition.signalAll(); } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } }
# 输出:
Thread-0 plan to produce (60), actually produce (60), depot size (60)
Thread-1 plan to consume (100), actutally consume (60), depot size (0)
Thread-2 plan to produce (90), actually produce (90), depot size (90)
Thread-3 plan to consume (40), actutally consume (40), depot size (50)
Thread-1 plan to consume (100), actutally consume (40), depot size (10)
# 有四个线程参与了这个过程,两个生产者,两个消费者
# 这是几个月之后的补充。。。。。。。。手动笑哭。
# 几个月之后,我重新回顾了这些内容。。。发现了上面的代码有坑!!!
# 首先我们来重现此坑
public static void main(String[] args) { Depot depot = new Depot(100); Producer producer = new Producer(depot); Consumer consumer = new Consumer(depot); for (int i = 0; i < 10; i++) { producer.produce(50); } for (int i = 0; i < 50; i++) { consumer.consume(10); } }
- main 方法是这个样子,在这种情况下,有时候会出现程序卡住的情况
- 用jstack看了一下堆栈信息,发现有几个consumer线程一直处于locked状态,但是已经没有人去唤醒他们了
- 分析了一下,其实原因很明显,我们在produce时,唤醒consumer使用的是signal(),最后一个生产者在唤醒某一个消费者之后,该消费者消费完了就再也没有生产者了,这时剩下的消费者线程就没有人唤醒他们了。。。换成signalAll()就ok了。
# 还有一个需要注意的是进入 await()的判断条件一定要使用while, 尽量不要使用if, 这个问题我会在 synchronized 实现的生产者-消费者模块中给出原因