生產者/消費者模式是爲了解耦消費者和生產者而產生的,其原理很是地簡單。總的來講就是生產者和消費者之間不直接通訊,而是藉助一個第三方(一般是阻塞隊列)
,第三方也成爲臨界資源,同一時間只容許一條線程對其進行操做。java
notify/wait
機制實現全部的註釋都寫在代碼中,在這裏咱們模仿在水桶中存水和取水的過程:bash
Main.java
ide
package com.wokao66.consumerProvider;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 測試
* @author: huangjiawei
* @since: 2018年4月3日
* @version: $Revision$ $Date$ $LastChangedBy$
*/
public class Main {
public static void main(String[] args) {
/**
* 新建一個水桶,存放全部的水,剛開始水桶是空的,容量爲5L
*/
List<Water> waterList = new ArrayList<>(5);
ExecutorService executors = Executors.newFixedThreadPool(10);
WaterProvider provider = new WaterProvider(waterList);
WaterConsumer consumer = new WaterConsumer(waterList);
executors.execute(provider);
executors.execute(consumer);
}
}
複製代碼
WaterProvider.java
測試
package com.wokao66.consumerProvider;
import java.util.List;
/**
* 往桶裏加水的生產者
* @author: huangjiawei
* @since: 2018年4月3日
* @version: $Revision$ $Date$ $LastChangedBy$
*/
public class WaterProvider implements Runnable {
/**
* 這是咱們的水桶(10L)
*/
private List<Water> waterList = null;
/**
* 初始化水桶,也就是緩衝區
*/
public WaterProvider(List<Water> waterList) {
this.waterList = waterList;
}
@Override
public void run() {
/**
* 循環任務,也就是這個任務會執行屢次,沒有明確的break語句或者異常,該任務不會終止
*/
while (true) {
/**
* 這裏得到waterList的鎖,以前說過notify、wait的使用必須先得到鎖
*/
synchronized (waterList) {
/**
* 判斷是否是滿了,滿了就不生產了
*/
while (waterList.size() == 5) {
try {
/**
* 這裏將所釋放掉waterList的鎖
*/
waterList.wait();
} catch (InterruptedException e) {}
}
/**
* 若是尚未滿,那麼就加1L水進去,加進去以前
*/
waterList.add(new Water());
System.err.println("生產了1L水,如今水桶有:" + waterList.size() + "L水");
try {
/**
* sleep方法是不會釋放鎖的
*/
Thread.sleep(1000);
} catch (InterruptedException e) {}
/**
* 我通知全部的消費者來消費
*/
waterList.notifyAll();
}
}
}
}
複製代碼
WaterConsumer.java
ui
package com.wokao66.consumerProvider;
import java.util.List;
/**
* 往桶裏取水的消費者
* @author: huangjiawei
* @since: 2018年4月3日
* @version: $Revision$ $Date$ $LastChangedBy$
*/
public class WaterConsumer implements Runnable {
private List<Water> waterList;
public WaterConsumer(List<Water> waterList) {
this.waterList = waterList;
}
@Override
public void run() {
/**
* 循環任務,也就是這個任務會執行屢次,沒有明確的break語句或者異常,該任務不會終止
*/
while (true) {
/**
* 得到鎖
*/
synchronized (waterList) {
/**
* 證實沒有水能夠消費
*/
while (waterList.isEmpty()) {
try {
/**
* 釋放鎖
*/
waterList.wait();
} catch (InterruptedException e) {}
}
/**
* 每次我都移動第一個元素
*/
waterList.remove(0);
System.err.println("消費了1L水,如今水桶有:" + waterList.size() + "L水");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
/**
* 通知生產者生產
*/
waterList.notifyAll();
}
}
}
}
複製代碼
Water.java
this
package com.wokao66.consumerProvider;
/**
* 水這種類型
* @author: huangjiawei
* @since: 2018年4月3日
* @version: $Revision$ $Date$ $LastChangedBy$
*/
public class Water {
/**
* 單位L
*/
private String unit;
public String getUnit() {
return unit;
}
public void setUnit(String unit) {
this.unit = unit;
}
}
複製代碼
執行結果:spa
生產了1L水,如今水桶有:1L水
生產了1L水,如今水桶有:2L水
消費了1L水,如今水桶有:1L水
消費了1L水,如今水桶有:0L水
生產了1L水,如今水桶有:1L水
生產了1L水,如今水桶有:2L水
消費了1L水,如今水桶有:1L水
消費了1L水,如今水桶有:0L水
生產了1L水,如今水桶有:1L水
消費了1L水,如今水桶有:0L水
生產了1L水,如今水桶有:1L水
生產了1L水,如今水桶有:2L水
生產了1L水,如今水桶有:3L水
生產了1L水,如今水桶有:4L水
生產了1L水,如今水桶有:5L水
消費了1L水,如今水桶有:4L水
消費了1L水,如今水桶有:3L水
消費了1L水,如今水桶有:2L水
消費了1L水,如今水桶有:1L水
複製代碼
執行結果可能會不一致,但數據正確便可!線程