java之生产者消费者模式了解wait以及notify的使用
2016-11-17 本文已影响162人
Java面试官
老规矩,先给源码,再进行分析:
Main.java 主要用来测试用例
package ConsumerProducer;
public class Main {
public static void main(String[] args) throws InterruptedException {
EventStorage storage = new EventStorage();
Producer producer = new Producer(storage);
Thread thread = new Thread(producer);
Consumer consumer = new Consumer(storage);
Thread thread2 = new Thread(consumer);
thread2.start();
thread.start();
}
}
EventStorage.java 主要用来操作数据
package ConsumerProducer;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
public class EventStorage {
private int maxSize;
private List<Date> storage;
public EventStorage() {
maxSize = 10;
storage = new LinkedList<>();
}
public synchronized void set() {
while (storage.size() == maxSize) {
try {
wait(); //一旦货存量达到阀值,便调用wait使其等待
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
storage.add(new Date());
System.out.printf("Set: %d", storage.size());
notifyAll(); //唤醒所有等待的线程
}
public synchronized void get() {
while (storage.size() == 0) {
try {
wait(); //一旦货存量为0,便调用wait使其等待
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.printf("Get: %d:%s", storage.size(), ((LinkedList<?>) storage).poll());
System.out.println();
notifyAll(); //唤醒所有等待的线程
}
}
Consumer.java
package ConsumerProducer;
public class Consumer implements Runnable {
private EventStorage storage;
public Consumer(EventStorage storage) {
// TODO Auto-generated constructor stub
this.storage = storage;
}
/**
* @Title: run
* @Description: TODO
*/
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 10; i++) {
System.out.println("get第"+i+"次");
storage.get();
}
}
}
Producer.java
package ConsumerProducer;
public class Producer implements Runnable {
private EventStorage storage;
public Producer(EventStorage storage) {
// TODO Auto-generated constructor stub
this.storage = storage;
}
/**
* @Title: run
* @Description: TODO
*/
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 10; i++) {
System.out.println("set第"+i+"次");
storage.set();
}
}
}
如何使用该demo:
创建项目,直接复制源码即可
分析:
关于同步代码块synchronized的这里就不解释了,主要说说我一直不会使用的wait和notify,从我给出的这个demo可以看出wait和notify都是在对象获得了锁的时候使用,为什么一定要等获得锁的时候才能使用呢?
这是因为wait和notify有可能会产生竞态条件(Race Condition),导致可能在生产者还没wait之前,消费者就已经notifyAll了,这样的话,生产者会一直等下去。而如果在没有获得锁的情况下如果使用wait以及notify的话会抛出java.lang.IllegalMonitorStateException的异常。
Note:发布的这些文章全都是自己边学边总结的,难免有纰漏,如果发现有不足的地方,希望可以指出来,一起学习。
开源爱好者,相信开源的力量必将改变世界:
osc:https://git.oschina.net/xi_fan
github:https://github.com/wiatingpub