Java併發學習--生產者/消費者模式
阿新 • • 發佈:2018-12-24
生產者/消費者模式是面向過程的一種高效設計模式。
生產者/消費者模式定義:
生產者消費者模式是通過一個容器來解決生產者和消費者的強耦合問題。生產者和消費者彼此之間不直接通訊,而通過阻塞佇列來進行通訊,所以生產者生產完資料之後不用等待消費者處理,直接扔給阻塞佇列,消費者不找生產者要資料,而是直接從阻塞佇列裡取,阻塞佇列就相當於一個緩衝區,平衡了生產者和消費者的處理能力。
這個阻塞佇列就是用來給生產者和消費者解耦的。縱觀大多數設計模式,都會找一個第三者出來進行解耦,如工廠模式的第三者是工廠類,模板模式的第三者是模板類。在學習一些設計模式的過程中,如果先找到這個模式的第三者,能幫助我們快速熟悉一個設計模式。
生產者/消費者模式原理:
1、生產者僅僅在倉庫未滿時進行成產,滿倉則停止生產。
2、消費者僅僅在倉庫有存量時才進行消費,否則停止消費。
3、生產者生產出產品後將通知消費者進行消費。
4、消費者停止消費時將通知生產者開始生產。
下面用程式碼來解釋一下生產者/消費者模式
1、定義一個倉庫,也就是產品管理類
/**
* 管理類
* @author Administrator
*
*/
public class ProductManager {
//快取最大數量
private static final int MAX = 100;
//當前數量
private static int current = 60;
//構造方法
private ProductManager(){};
//獲取單例
public static ProductManager getInstance(){
return ProductSingleton.productManager;
}
//靜態內部類
private static class ProductSingleton{
static ProductManager productManager = new ProductManager();
}
//建立商品
public synchronized void setProduct(){
while (current > MAX/2){
//停止生產
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
current++;
System.out.println("++++當前執行緒:"+Thread.currentThread().getName() +
"--生產了一個產品,當前庫存還有:"+ current + "個");
//通知消費者執行緒
notifyAll();
}
//消費商品
public synchronized void getProduct(){
while(current < 1){
try {
// 停止消費
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
current--;
System.out.println("----當前執行緒:"+Thread.currentThread().getName() +
"--消費了一個產品,當前庫存還有:"+ current + "個");
//通知生產者執行緒
notifyAll();
}
}
倉庫只有有個,所以採用的單例模式建立倉庫例項。倉庫中定義了容量以及當前存量,以及生產的方法和消費的方法,用於生產者和消費者呼叫。
2、定義生產者執行緒。
/**
* 生產者執行緒
* @author Administrator
*
*/
public class Producer implements Runnable{
@Override
public void run() {
while(true){
//獲取單例,生產產品
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ProductManager.getInstance().setProduct();
}
}
}
3、定義消費者執行緒
/**
* 消費者執行緒
* @author Administrator
*
*/
public class Consumer implements Runnable{
@Override
public void run() {
while(true){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ProductManager.getInstance().getProduct();
}
}
}
4、測試
/**
* 測試
* @author Administrator
*
*/
public class Test {
public static void main(String[] args) {
startProducer();
startConsumer();
}
private static void startConsumer() {
System.out.println("消費者執行緒執行開始");
int iThreadSize = 10;
Executor pool = Executors.newFixedThreadPool(iThreadSize);
for(int i = 0 ; i < iThreadSize ; i++){
pool.execute(new Thread(new Consumer()));
}
System.out.println("消費者執行緒執行結束");
}
private static void startProducer() {
System.out.println("生產者執行緒執行開始");
int iThreadSize = 10;
Executor pool = Executors.newFixedThreadPool(iThreadSize);
for(int i = 0 ; i < iThreadSize ; i++){
pool.execute(new Thread(new Producer()));
}
System.out.println("生產者執行緒執行結束");
}
}
測試中,我開啟了10個生產者,10個消費者,當然,實際當中也有差距。接下來就讓我們的整個系統跑起來看看。
生產者執行緒執行開始
生產者執行緒執行結束
消費者執行緒執行開始
消費者執行緒執行結束
----當前執行緒:pool-2-thread-9--消費了一個產品,當前庫存還有:59個
----當前執行緒:pool-2-thread-10--消費了一個產品,當前庫存還有:58個
----當前執行緒:pool-2-thread-6--消費了一個產品,當前庫存還有:57個
----當前執行緒:pool-2-thread-1--消費了一個產品,當前庫存還有:56個
----當前執行緒:pool-2-thread-4--消費了一個產品,當前庫存還有:55個
----當前執行緒:pool-2-thread-5--消費了一個產品,當前庫存還有:54個
----當前執行緒:pool-2-thread-8--消費了一個產品,當前庫存還有:53個
----當前執行緒:pool-2-thread-2--消費了一個產品,當前庫存還有:52個
----當前執行緒:pool-2-thread-3--消費了一個產品,當前庫存還有:51個
----當前執行緒:pool-2-thread-7--消費了一個產品,當前庫存還有:50個
++++當前執行緒:pool-1-thread-8--生產了一個產品,當前庫存還有:51個
----當前執行緒:pool-2-thread-10--消費了一個產品,當前庫存還有:50個
++++當前執行緒:pool-1-thread-9--生產了一個產品,當前庫存還有:51個
----當前執行緒:pool-2-thread-9--消費了一個產品,當前庫存還有:50個
++++當前執行緒:pool-1-thread-5--生產了一個產品,當前庫存還有:51個
----當前執行緒:pool-2-thread-1--消費了一個產品,當前庫存還有:50個
++++當前執行緒:pool-1-thread-10--生產了一個產品,當前庫存還有:51個
----當前執行緒:pool-2-thread-4--消費了一個產品,當前庫存還有:50個
----當前執行緒:pool-2-thread-3--消費了一個產品,當前庫存還有:49個
...
因為是在迴圈當中個,所以這整個程式會一直跑下去,看輸出結果,有條不紊,各司己職。
以上就是生產和消費者的介紹、原理和使用。