# 代码
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 Depot { // 仓库最大容量 private int capacity; // 仓库目前容量 private int size; public Depot(int capacity) { this.size = 0; this.capacity = capacity; } public synchronized void produce(int val) { try { int surplus = val; while (surplus > 0) { while (size >= capacity) { wait(); } 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); notify(); } } catch (InterruptedException e) { e.printStackTrace(); } } public synchronized void consume(int val) { try { int surplus = val; while (surplus > 0) { while (size <= 0) { wait(); } 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); notify(); } } catch (InterruptedException e) { e.printStackTrace(); } } } 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(); } }
# 输出:
Thread-0 plan to produce (60), actually produce (60), depot size (60)
Thread-3 plan to consume (40), actutally consume (40), depot size (20)
Thread-2 plan to produce (90), actually produce (80), depot size (100)
Thread-1 plan to consume (100), actutally consume (100), depot size (0)
Thread-2 plan to produce (90), actually produce (10), depot size (10)
# 有四个线程参与了这个过程,两个生产者,两个消费者
# 时隔多月,我们再来考虑一种业务场景,假设要求是,生产的时候的条件是:要么全部生产,要么全部不生产;消费的条件也是:要么全部消费,要么不消费;此时,实现的代码可能如下:
public class Common { 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); } } } class Depot { // 仓库最大容量 private int capacity; // 仓库目前容量 private int size; public Depot(int capacity) { this.size = 0; this.capacity = capacity; } public synchronized void produce(int val) { try { if (size + val > capacity) { wait(); } size += val; System.out.printf("%s produce (%d), depot size (%d) ", Thread.currentThread().getName(), val, size); notifyAll(); } catch (InterruptedException e) { e.printStackTrace(); } } public synchronized void consume(int val) { try { if (size - val < 0) { wait(); } size -= val; System.out.printf("%s consume (%d), depot size (%d) ", Thread.currentThread().getName(), val, size); notifyAll(); } catch (InterruptedException e) { e.printStackTrace(); } } } 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(); } }
- 运行一下,你会发现仓库中的数量会出现负的情况,如果你改变生产者和消费者的线程数,还有可能出现超过仓库容量的情况,这该怎么解决呢?
- 其实解决方法很简单,把wait()方法的判断语句由if换成while即可;
- 我们来深究原因,以消费者为例,if的情况下,消费线程由wait状态切换到运行状态的时候,不再去判断仓库中的现有的存储量是否满足消费,此时该消费线程有可能由其他的消费线程唤醒,而其他的线程早已经把仓库消费完了,该线程再去消费,仓库自然就变成负的了。而while则不同,判断条件为while时,每次消费者线程被唤醒,均会做一次判断。
- 其实在jdk文档中,对这种情况已经作了强调说明, 如下图所示
! 多读官方文档,多读源码! 手动笑哭。。。