1. 程式人生 > >併發設計模式之生產者-消費者模式

併發設計模式之生產者-消費者模式

生產者-消費者模式是一個經典的多執行緒設計模式,它為多執行緒間的協作提供了良好的解決方案。在生產者-消費者模式中,通常有兩類執行緒,即若干個生產者和若干個消費者執行緒。生產者執行緒負責提交使用者請求,消費者執行緒則負責處理生產者提交的任務。生產者和消費者之間通過共享記憶體緩衝區進行通訊

如圖展示了生產者-消費者模式的基本結構。3個生產者執行緒將在任務提交到共享記憶體緩衝區,消費者執行緒並不直接與生產者執行緒通訊,而在共享記憶體緩衝區中獲取任務,並進行處理

producerconsumer

生產者-消費者模式中的記憶體緩衝區的主要功能是資料在多執行緒間的共享。此外,通過該緩衝區,可以緩解生產者和消費者間的效能差

生產者-消費者模式的核心元件是共享記憶體緩衝區,它作為生產者和消費者間的通訊橋樑,避免了生產者和消費者的直接通訊,從而將生產者和消費者進行解耦。生產者不需要知道消費者的存在,消費者也不需要知道生產者的存在。同時,由於記憶體緩衝區的存在,允許生產者和消費者在執行速度上存在時間差,無論是生產者在某一區域性時間內速度高於消費者,或者消費者在區域性時間內高於生產者,都可以通過共享記憶體緩衝區得到緩解,確保系統正常執行

生產者-消費者模式的主要角色有:生產者、消費者、記憶體緩衝區、任務、Main

  • 生產者:用於提交使用者請求,提取使用者任務,並裝入記憶體緩衝區
  • 消費者:在記憶體緩衝區中提取並處理任務
  • 記憶體緩衝區:快取生產者提交的任務或資料,供消費者使用
  • 任務:生產者想記憶體緩衝區提交的資料結構
  • Main:使用生產者和消費者的客戶端

pcuml

上圖顯示了生產者-消費者模式一種實現的具體結構

其中,BlockingQueue充當了共享記憶體緩衝區,使用者維護任務或資料佇列(PCData物件)。PCData物件表示一個生產任務,或者相關任務的資料。生產者物件和消費者物件均引用同一個BlockingQueue例項。生產者負責建立PCData物件,並將它加入BlockingQueue中,消費者則從BlockingQueue佇列中獲取PCData

下面實現一個基於生產者-消費者模式的求證書平方的並行程式

PCData作為生產者和消費者之間的共享資料模型,定義如下

package com.joyhwong;

public final class PCData {
	private final int intData;
	
	public PCData(int intData) {
		this.intData = intData;
	}
	
	public PCData(String d) {
		this.intData = Integer.valueOf(d);
	}
	
	public int getData() {
		return intData;
	}
	
	@Override
	public String toString() {
		return "data: " + intData;
	}
}

生產者執行緒的實現如下

package com.joyhwong;

import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class Producer implements Runnable {
	private volatile boolean isRunning = true;
	private BlockingQueue<PCData> queue;
	private static AtomicInteger count = new AtomicInteger();
	private static final int SLEEPTIME = 1000;

	public Producer(BlockingQueue<PCData> queue) {
		this.queue = queue;
	}

	@Override
	public void run() {
		PCData data = null;
		Random random = new Random();

		System.out.println("start producer id = " + Thread.currentThread().getId());

		try {
			while (isRunning) {
				Thread.sleep(random.nextInt(SLEEPTIME));
				data = new PCData(count.incrementAndGet());
				System.out.println(data + " is put into queue");
				if (!queue.offer(data, 2, TimeUnit.SECONDS)) {
					System.out.println("failed to put data: " + data);
				}
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
			Thread.currentThread().interrupt();
		}
	}
	
	public void stop() {
		isRunning = false;
	}
}

消費者實現如下,它從BlockingQueue佇列中取出PCData物件,並進行相應的計算

package com.joyhwong;

import java.text.MessageFormat;
import java.util.Random;
import java.util.concurrent.BlockingQueue;

public class Consumer implements Runnable {
	private BlockingQueue<PCData> queue;
	private static final int SLEEPTIME = 1000;
	
	public Consumer(BlockingQueue<PCData> queue) {
		this.queue = queue;
	}
	
	@Override
	public void run() {
		System.out.println("Start Consumer id = " + Thread.currentThread().getId());
		Random random = new Random();
		try {
			while (true) {
				PCData data = queue.take();
				if (null != data) {
					int re = data.getData() * data.getData();
					System.out.println(MessageFormat.format("{0}*{1}={2}", data.getData(), data.getData(), re));
					Thread.sleep(random.nextInt(SLEEPTIME));
				}
			} 
		} catch (InterruptedException e) {
			e.printStackTrace();
			Thread.currentThread().interrupt();
		}
	}
}

在主函式中,建立3個生產者和3個消費者,並讓它們協作執行。在主函式的實現中,定義LinkedBlockingQueue作為BlockingQueue的實現類

package com.joyhwong;

import java.text.MessageFormat;
import java.util.Random;
import java.util.concurrent.BlockingQueue;

public class Consumer implements Runnable {
	private BlockingQueue<PCData> queue;
	private static final int SLEEPTIME = 1000;
	
	public Consumer(BlockingQueue<PCData> queue) {
		this.queue = queue;
	}
	
	@Override
	public void run() {
		System.out.println("Start Consumer id = " + Thread.currentThread().getId());
		Random random = new Random();
		try {
			while (true) {
				PCData data = queue.take();
				if (null != data) {
					int re = data.getData() * data.getData();
					System.out.println(MessageFormat.format("{0}*{1}={2}", data.getData(), data.getData(), re));
					Thread.sleep(random.nextInt(SLEEPTIME));
				}
			} 
		} catch (InterruptedException e) {
			e.printStackTrace();
			Thread.currentThread().interrupt();
		}
	}
}

生產者-消費者模式能夠很好地對生產者和消費者執行緒進行解耦,優化了系統整體結構。同時,由於緩衝區的作用,允許生產者執行緒和消費者執行緒存在執行上的效能差異,從一定程度上緩解了效能瓶頸對系統性能的影響。

相關推薦

併發設計模式生產者-消費者模式

生產者-消費者模式是一個經典的多執行緒設計模式,它為多執行緒間的協作提供了良好的解決方案。在生產者-消費者模式中,通常有兩類執行緒,即若干個生產者和若干個消費者執行緒。生產者執行緒負責提交使用者請求,消費者執行緒則負責處理生產者提交的任務。生產者和消費者之間通過共享記憶

java 多執行緒併發系列 生產者消費者模式的兩種實現

生產者消費者模式是併發、多執行緒程式設計中經典的設計模式,生產者和消費者通過分離的執行工作解耦,簡化了開發模式,生產者和消費者可以以不同的速度生產和消費資料。真實世界中的生產者消費者模式生產者和消費者模式在生活當中隨處可見,它描述的是協調與協作的關係。比如一個人正在準備食物(

設計模式06---生產者消費者模式

生產者和消費者指的是兩個不同的執行緒類物件,操作統一資源的情況。具體的操作流程如下: (1)生產者負責生成資料,消費者負責取走資料; (2)生產者每生產完一組資料之後,消費者就要取走一組資料。 一. 直白寫法 1. info類 1 public class Info { 2

聊聊併發(十)生產者消費者模式

本文首發於InfoQ   作者:方騰飛  校對:張龍 在併發程式設計中使用生產者和消費者模式能夠解決絕大多數併發問題。該模式通過平衡生產執行緒和消費執行緒的工作能力來提高程式的整體處理資料的速度。 為什麼要使用生產者和消費者模式 線上程世界裡,生產者就是生產資料的執行緒,消費者就是消費資料的執

一次任務的實踐,解決每秒最大併發次數的問題 -- 生產者消費者模式

一次任務的實踐 – 生產者消費者模式 任務描述: 該任務會呼叫騰訊地圖介面根據經緯度來得到詳細地址,但是該介面有每秒併發限制(5次/秒/介面/Key),故寫一個消費者和生產者模式工具類。 生產者保證每六次生產,時間相差一秒(即第一次和第六次生產的時間相差一

多執行緒生產者/消費者模式(值操作)

1、一個生產者,一個消費者(值操作) 本小節是典型的單個生產者,單個消費者,生產物件為值的Demo 如下,我們假設ValueObject .value為生產的值,當value的值為 “”(空串)時,我們認為生產出來的物件已被消費,當value的值不為空串時,

反應器模式 vs 生產者消費者模式

相似點: 從結構上,反應器模式有點類似生產者消費者模式,即有一個或多個生產者將事件放入一個Queue中,而一個或多個消費者主動的從這個Queue中Poll事件來處理; 不同點: Reactor模式則並沒有Queue來做緩衝,每當一個Event輸入到Reactor 反應器之後,該Reactor 反應器會主

java併發----實現生產者/消費者模式(操作值&一對一交替列印)

一、實現生產者/消費者模式 1、一生產與一消費:操作值 利用synchronized 實現,程式碼如下: public class Producer { private String lock; public Producer(String lock){ this.loc

設計模式】2.工廠設計模式生產者消費者問題)

catch 設計 star 機制 print boolean 結果 try producer 生產者消費者模型 與 多線程 生產者、消費者在同一時間內共用同一存儲空間, 生產者向共享空間生產數據, 而消費者取走共享的數據。、 經典問題描述: 生產者不斷交替地生產兩組數據“姓

生產者/消費者模式深入理解

模板 必須 winapi 協議 針對 sso 額外 fill 功能實現 #include <windows.h> #include <iostream> const unsigned short SIZE_OF_BUFFER = 2; //緩沖區長

生產者/消費者模式(阻塞佇列) 一個經典的併發模型

生產消費者模式也是關於執行緒阻塞的問題,生產消費者模式是通過觀察者模式來實現的。之前在編寫一個通訊軟體的時候用到了這種模式,通過維護一個BlockingQueue來完成Socket的訊息傳送,後來讀書時看到在伺服器開發時三層模型中的Service層在呼叫Dao層的時候也是通過這種模式來呼叫的,具體怎

設計模式-生產消費者

看到這裡需先注意,消費量應大於生產量避免OOM package com.desigin.producerConsumer;import java.util.concurrent.BlockingQueue; public class Consumer implements Runnabl

多執行緒設計模式:第三篇 - 生產者-消費者模式和讀寫鎖模式

一,生產者-消費者模式         生產者-消費者模式是比較常見的一種模式,當生產者和消費者都只有一個的時候,這種模式也被稱為 Pipe模式,即管道模式。      &nb

python多執行緒Lock版生產者消費者模式

python多執行緒之lock版生產者消費者模式,謹以此文記之。 python多執行緒技術,仁者見仁智者見智,有道其雞肋,有道其乖張。暫且不去評論。本文僅述其淺淺的應用罷了。如下見祥例說明。 本文利用多執行緒技術,模擬在python爬蟲環境中的應用,分為生產者部分和消費者部分,也就是將一

併發程式設計:生產者-消費者模式

        除了Futrue模式和Master-Worker模式,生產者-消費者模式也是一個非常經典的多執行緒模式。在生產者-消費者模式中,通常有兩類執行緒(即N+1個生產者和N+1個消費者的執行緒),生產者負責提交使用者請求,消費者則負責進行具體的業務處理,生產者和消費

Java併發學習--生產者/消費者模式

生產者/消費者模式是面向過程的一種高效設計模式。 生產者/消費者模式定義: 生產者消費者模式是通過一個容器來解決生產者和消費者的強耦合問題。生產者和消費者彼此之間不直接通訊,而通過阻塞佇列來進行通訊,所以生產者生產完資料之後不用等待消費者處理,直接扔

設計模式-生產者消費者模式 常見場景: 某個模組負責產生資料,這些資料由另一個模組來負責處理。產生資料的模組,就形象地稱為生產者;而處理資料的模組,就稱為消費者。 該模式還需要有一個緩衝區處於生

常見場景: 某個模組負責產生資料,這些資料由另一個模組來負責處理。產生資料的模組,就形象地稱為生產者;而處理資料的模組,就稱為消費者。 該模式還需要有一個緩衝區處於生產者和消費者之間,作為一箇中介。生產者把資料放入緩衝區,而消費者從緩衝區取出資料 緩衝區作用 1. 解耦,生產者和消費者只依賴緩衝區,而不互

入坑JAVA多執行緒併發(五)生產者消費者模式

生產者消費者模式對於理解多執行緒是一個很經典,也很好的例子 資源類: class Resource{ //資源初始化個數 private int init; //資源最大個數 private int Max; p

【Java併發生產者-消費者模式簡單實現(模擬訊息佇列)

簡單的模擬了一個訊息佇列 Producer:生產者 Consumer:消費者 Message:訊息體 import java.util.concurrent.ArrayBlockingQueue; import java.util.c

轉:架構設計生產者/消費者模式[3]:環形緩衝區

原文:http://blog.csdn.net/program_think/article/details/4040068 前一個帖子提及了佇列緩衝區可能存在的效能問題及解決方法:環形緩衝區。今天就專門來描述一下這個話題。   為了防止有人給咱扣上“過度設計”的大帽子,事