學了生產者/消費者模式這麼久,今天終於來實現一下了,寫以前先複習一下生產者/消費者。java
生產者/消費者模式在操做系統中是個經典的進程同步問題,能夠使用「信號量」機制來解決,須要注意的點在下面有提到。緩存
寫以前先分析一下須要作的事情:ide
用LinkedHashMap當緩存,synchronized做爲同步鎖測試
定義一個緩存隊列this
public class PublicQueue<T> {
//數據插入的下標
private int putIndex = 0;
//最大容量
private int maxCount = 50;
//緩衝區
private LinkedHashMap<Integer, T> linkedHashMap = new LinkedHashMap<>();
/** * 往阻塞隊列添加數據 * @param msg */
public synchronized void put(T msg) {
//若是緩存的數據達到maxCount,阻塞
if (linkedHashMap.size() == maxCount) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
//沒有滿,就喚醒其餘全部線程
notifyAll();
}
//往緩存裏面存數據
linkedHashMap.put(putIndex, msg);
System.out.println("生產一個產品,當前商品下標爲:"+putIndex+"===文本爲:"+msg+"===緩存長度爲:"+linkedHashMap.size());
//更新putIndex
putIndex = (putIndex + 1 >= maxCount) ? (putIndex + 1) % maxCount : putIndex + 1;
}
/*** * 從阻塞隊列取數據 * @return */
public synchronized T get() {
//若是阻塞隊列爲空,就阻塞消費者
if (linkedHashMap.size() == 0) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
notifyAll();
}
//經過Iterator取數據,確保取出的數據是有序的
Iterator iterator = linkedHashMap.entrySet().iterator();
T t = null;
if (iterator.hasNext()) {
Map.Entry<Integer, T> entry = (Map.Entry<Integer, T>) iterator.next();
t = entry.getValue();
int index = entry.getKey();
linkedHashMap.remove(index);
System.out.println("消費一個產品,當前商品下標爲:"+index+"===文本爲:"+ t +"===緩存長度爲:"+linkedHashMap.size());
}
return t;
}
}
複製代碼
定義一個生產者線程spa
public class Provider extends Thread{
private PublicQueue publicQueue;
public Provider(PublicQueue publicQueue) {
this.publicQueue = publicQueue;
}
@Override
public void run() {
for (int i = 0; i < 60; i++) {
publicQueue.put(String.valueOf(i));
}
}
}
複製代碼
定義一個消費者線程操作系統
public class Consumer extends Thread{
private PublicQueue publicQueue;
public Consumer(PublicQueue publicQueue) {
this.publicQueue = publicQueue;
}
@Override
public void run() {
for (; ; ) {
publicQueue.get();
}
}
}
複製代碼
測試線程
public class ProviderConsumerTest {
public static void main(String[] args) {
PublicQueue publicQueue = new PublicQueue();
Provider provider = new Provider(publicQueue);
Consumer consumer = new Consumer(publicQueue);
provider.start();
consumer.start();
}
}
複製代碼
這個方式也是比較簡單的,直接使用Java提供的阻塞隊列便可code
public class PublicQueue<T> {
//緩衝區
private BlockingDeque<T> blockingDeque = new LinkedBlockingDeque<>(50);
public void add(T msg){
try {
blockingDeque.put(msg);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("生產一個產品,當前商品下標爲:"+"===文本爲:"+msg);
}
public T get(){
T t = null;
try {
t = blockingDeque.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("消費一個產品,當前商品下標爲:"+"===文本爲:"+t);
return t;
}
}
複製代碼