在这里咱们模拟一个生产者消费者问题。定义一个缓冲区,生产者生产数据并存入缓冲区,消费者从缓冲区中消费数据。缓冲区有固定大小,当缓冲区达到最大时生产者被挂起并等待消费者消费数据后再尝试将生产的数据加入缓冲区;当缓冲区数据量为0时,消费者被挂起直到有生产者向缓冲区中存入数据。java
咱们能够看到这个缓冲区是一个公共变量,因此缓冲区中数据的存放和取出都必须放置在一段synchronized修饰的同步代码中。ide
Java API的Object类提供了一组方法wait(),notify()和nofityAll()用于实现这个例子。this
示例代码:线程
首先咱们建立一个类来模拟实现一个阻塞数据缓冲池,这个缓冲池有一个链表结构用于缓冲数据,有一个整形变量用于定义数据缓冲区大小。一个set()方法用于模拟生产者向缓冲区内加入数据,一旦数据缓冲区满则挂起,成功插入数据后唤起全部消费者线程。一个get()方法用于模拟消费者从缓冲区中消费数据,一旦数据缓冲区空了则挂起,成功消费数据后唤起全部生产者线程。日志
public class EventStorage { private int maxSize; private LinkedList<Date> storage; public EventStorage() { maxSize = 10; storage = new LinkedList<Date>(); } public void set() { synchronized (Main.producerController) { while (storage.size() == maxSize) { try { Main.producerController.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } storage.add(new Date()); System.out.printf("%s: Add one. storge size: %d.\n", Thread.currentThread().getName(), storage.size()); } synchronized (Main.consumerController) { Main.consumerController.notifyAll(); } } public void get() { synchronized (Main.consumerController) { while (storage.size() == 0) { try { Main.consumerController.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("%s: Get one %s. Storge size: %d.\n", Thread.currentThread().getName(), storage.poll(), storage.size()); } synchronized (Main.producerController) { Main.producerController.notifyAll(); } } }
建立两个线程类用于模拟生产者和消费者。code
public class Producer implements Runnable{ private EventStorage eventStorage; public Producer(EventStorage eventStorage) { this.eventStorage = eventStorage; } @Override public void run() { eventStorage.set(); } }
public class Consumer implements Runnable{ private EventStorage eventStorage; public Consumer(EventStorage eventStorage) { this.eventStorage = eventStorage; } @Override public void run() { eventStorage.get(); } }
定义主方法类,在这里咱们启动20个消费者线程与20个生产者线程,其中生产者速度快,消费者速度慢。这样会致使生产者线程阻塞,等待消费者消费数据后被唤醒。get
public class Main { public static final Object producerController = new Object(); public static final Object consumerController = new Object(); public static void main(String[] args) { EventStorage eventStorage = new EventStorage(); Producer producer = new Producer(eventStorage); Consumer consumer = new Consumer(eventStorage); Thread[] threads1 = new Thread[20]; Thread[] threads2 = new Thread[20]; for (int i = 0; i < 20; i++) { threads1[i] = new Thread(producer, "Producer-" + i); threads2[i] = new Thread(consumer, "Consumer-" + i); } for (int i = 0; i < 20; i++) { threads1[i].start(); threads2[i].start(); } } }
查看控制台日日志,你会发现生产者快速加入10个数据到缓冲区,而后线程开始挂起,直到消费者开始消费数据,每次消费数据后生产者会被唤醒一次,并加入数据到缓冲区。最后20个生产者线程都执行完毕后,消费者线程才执行完毕。若是你想模拟消费者被阻塞只须要调整生产者速度慢于消费者速度。同步
Producer-0: Add one. storge size: 1. Producer-19: Add one. storge size: 2. Producer-18: Add one. storge size: 3. Producer-17: Add one. storge size: 4. Producer-16: Add one. storge size: 5. Producer-15: Add one. storge size: 6. Producer-14: Add one. storge size: 7. Producer-13: Add one. storge size: 8. Producer-12: Add one. storge size: 9. Producer-11: Add one. storge size: 10. Consumer-3: Get one Thu Nov 24 17:12:13 CST 2016. Storge size: 9. Producer-1: Add one. storge size: 10. Consumer-19: Get one Thu Nov 24 17:12:13 CST 2016. Storge size: 9. Producer-10: Add one. storge size: 10. Consumer-18: Get one Thu Nov 24 17:12:13 CST 2016. Storge size: 9. Producer-2: Add one. storge size: 10. Consumer-17: Get one Thu Nov 24 17:12:13 CST 2016. Storge size: 9. Producer-9: Add one. storge size: 10. Consumer-16: Get one Thu Nov 24 17:12:13 CST 2016. Storge size: 9. Producer-3: Add one. storge size: 10. Consumer-15: Get one Thu Nov 24 17:12:13 CST 2016. Storge size: 9. Producer-8: Add one. storge size: 10. Consumer-14: Get one Thu Nov 24 17:12:13 CST 2016. Storge size: 9. Producer-4: Add one. storge size: 10. Consumer-13: Get one Thu Nov 24 17:12:13 CST 2016. Storge size: 9. Producer-7: Add one. storge size: 10. Consumer-12: Get one Thu Nov 24 17:12:13 CST 2016. Storge size: 9. Producer-5: Add one. storge size: 10. Consumer-11: Get one Thu Nov 24 17:12:13 CST 2016. Storge size: 9. Producer-6: Add one. storge size: 10. Consumer-10: Get one Thu Nov 24 17:12:14 CST 2016. Storge size: 9. Consumer-9: Get one Thu Nov 24 17:12:15 CST 2016. Storge size: 8. Consumer-8: Get one Thu Nov 24 17:12:16 CST 2016. Storge size: 7. Consumer-7: Get one Thu Nov 24 17:12:17 CST 2016. Storge size: 6. Consumer-6: Get one Thu Nov 24 17:12:18 CST 2016. Storge size: 5. Consumer-5: Get one Thu Nov 24 17:12:19 CST 2016. Storge size: 4. Consumer-4: Get one Thu Nov 24 17:12:20 CST 2016. Storge size: 3. Consumer-2: Get one Thu Nov 24 17:12:21 CST 2016. Storge size: 2. Consumer-1: Get one Thu Nov 24 17:12:22 CST 2016. Storge size: 1. Consumer-0: Get one Thu Nov 24 17:12:23 CST 2016. Storge size: 0.