并发编程中有个经典问题:
生产消费者问题。
我们有一个数据缓冲区,一个或多个生产者往其中存入对象,另外一个或多个消费者从中取走。
因此,该数据缓冲区是一个共享数据结构,我们需要对其添加读取同步机制,但是我们还需要一些限制。
如果缓冲区满了,生产者不能继续向其中写入;反过来如果缓冲区空了,消费者也不能继续读取。
对于这种情况,Java提供了wait(),notify()和notifyAll()方法。
一个线程可以在同步代码块中调用wait()方法。如果它在同步块之外调用wait()方法,JVM将抛出IllegalMonitorStateException。
当线程调用wait()方法,JVM将该线程睡眠并且释放控制同步代码块的对象,并允许其他线程去执行。
如果需要再次唤醒该线程,只需要调用notify()或notifyAll()方法。
我们有一个数据缓冲区,一个或多个生产者往其中存入对象,另外一个或多个消费者从中取走。
因此,该数据缓冲区是一个共享数据结构,我们需要对其添加读取同步机制,但是我们还需要一些限制。
如果缓冲区满了,生产者不能继续向其中写入;反过来如果缓冲区空了,消费者也不能继续读取。
对于这种情况,Java提供了wait(),notify()和notifyAll()方法。
一个线程可以在同步代码块中调用wait()方法。如果它在同步块之外调用wait()方法,JVM将抛出IllegalMonitorStateException。
当线程调用wait()方法,JVM将该线程睡眠并且释放控制同步代码块的对象,并允许其他线程去执行。
如果需要再次唤醒该线程,只需要调用notify()或notifyAll()方法。
本例中,你将学习如何使用synchronized关键字和wait(), notify(), and notifyAll()方法去实现生产-消费者问题。
缓冲区类:
EventStorage.java
package com.dylan.thread.ch2.c03.task; import java.util.Date; import java.util.LinkedList; import java.util.List; /** * This class implements an Event storage. Producers will storage * events in it and Consumers will process them. An event will * be a java.util.Date object * */ public class EventStorage { /** * Maximum size of the storage */ private int maxSize; /** * Storage of events */ private List<Date> storage; /** * Constructor of the class. Initializes the attributes. */ public EventStorage(){ maxSize=10; storage=new LinkedList<>(); } /** * This method creates and storage an event. */ public synchronized void set(){ while (storage.size()==maxSize){ try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } storage.add(new Date()); System.out.printf("Set: %d",storage.size()); notify(); } /** * This method delete the first event of the storage. */ public synchronized void get(){ while (storage.size()==0){ try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.printf("Get: %d: %s",storage.size(),((LinkedList<?>)storage).poll()); notify(); } }
生产者:
Producer.java
package com.dylan.thread.ch2.c03.task; /** * This class implements a producer of events. * */ public class Producer implements Runnable { /** * Store to work with */ private EventStorage storage; /** * Constructor of the class. Initialize the storage. * @param storage The store to work with */ public Producer(EventStorage storage){ this.storage=storage; } /** * Core method of the producer. Generates 100 events. */ @Override public void run() { for (int i=0; i<100; i++){ storage.set(); } } }
消费者:
Consumer.java
package com.dylan.thread.ch2.c03.task; /** * This class implements a consumer of events. * */ public class Consumer implements Runnable { /** * Store to work with */ private EventStorage storage; /** * Constructor of the class. Initialize the storage * @param storage The store to work with */ public Consumer(EventStorage storage){ this.storage=storage; } /** * Core method for the consumer. Consume 100 events */ @Override public void run() { for (int i=0; i<100; i++){ storage.get(); } } }
主类:
Main.java
package com.dylan.thread.ch2.c03.core; import com.dylan.thread.ch2.c03.task.Consumer; import com.dylan.thread.ch2.c03.task.EventStorage; import com.dylan.thread.ch2.c03.task.Producer; /** * Main class of the example */ public class Main { /** * Main method of the example */ public static void main(String[] args) { // Creates an event storage EventStorage storage=new EventStorage(); // Creates a Producer and a Thread to run it Producer producer=new Producer(storage); Thread thread1=new Thread(producer); // Creates a Consumer and a Thread to run it Consumer consumer=new Consumer(storage); Thread thread2=new Thread(consumer); // Starts the thread thread2.start(); thread1.start(); } }
运行结果:
Set: 1
Set: 2
Set: 3
Set: 4
Set: 5
Set: 6
Set: 7
Set: 8
Set: 9
Set: 10
Get: 10: Fri May 11 22:31:02 GMT+08:00 2018
Get: 9: Fri May 11 22:31:02 GMT+08:00 2018
Get: 8: Fri May 11 22:31:02 GMT+08:00 2018
Get: 7: Fri May 11 22:31:02 GMT+08:00 2018
Get: 6: Fri May 11 22:31:02 GMT+08:00 2018
Get: 5: Fri May 11 22:31:02 GMT+08:00 2018
Get: 4: Fri May 11 22:31:02 GMT+08:00 2018
Get: 3: Fri May 11 22:31:02 GMT+08:00 2018
Get: 2: Fri May 11 22:31:02 GMT+08:00 2018
Get: 1: Fri May 11 22:31:02 GMT+08:00 2018
Set: 1
Set: 2
...