1. 程式人生 > >多執行緒之六:併發設計模式

多執行緒之六:併發設計模式

什麼是設計模式

    在軟體工程中,設計模式(design pattern)是對軟體設計中普遍存在(反覆出現)的各種問題 ,所提出的解決方案

    架構模式 – MVC – 分層

    設計模式提煉系統中的元件

    程式碼模式(成例 Idiom

        – 低層次,與編碼直接相關

        – DCL

不變模式

    一個類的內部狀態建立後,在整個生命期間都不會發生變化時,就是不變類

    不變模式不需要同

程式碼示例:

public final class Product {
	//確保無子類
	private final String no;
	//私有屬性,不會被其他物件獲取
	private final String name;
	//final保證屬性不會被2次賦值
	private final double price;
	//在建立物件時,必須指定資料
	public Product(String no, String name, double price) { 
		super();
		//因為建立之後,無法進行修改
		this.no = no;
		this.name = name;
		this.price = price;
	}
	public String getNo() {
		return no;
	}
	public String getName() {
		return name;
	}
	public double getPrice() {
		return price;
	}
}

        JDK中的不變類:

            java.lang.String

            java.lang.Boolean

            java.lang.Byte

            java.lang.Character

            java.lang.Double

            java.lang.Float

            java.lang.Integer

            java.lang.Long

            java.lang.Short

        Future模式

        核心思想

            非同步調

主執行緒可以獲取到目標執行緒的處理結果

        與join()的區別

join():主執行緒需要阻塞直到目標執行緒執行結束

Future:啟動了目標執行緒之後主執行緒還可以繼續其他操作,直到需要取目標執行緒的處理結果的時候才進行等待。

主要構造:

程式碼示例:

public interface Data {
 public String getResult ();
}
public class FutureData implements Data {
 protected RealData realdata = null; //FutureData是RealData的包裝
 protected boolean isReady = false;
 public synchronized void setRealData(RealData realdata) {
	 if (isReady) {
		return;
	 }
	 this.realdata = realdata;
	 isReady = true;
	 notifyAll(); //RealData已經被注入,通知getResult()
 }
 public synchronized String getResult() { //會等待RealData構造完成
	 while (!isReady) {
		 try {
			wait(); //一直等待,知道RealData被注入
		 } catch (InterruptedException e) {
		 }
	 }
	return realdata.result; //由RealData實現
 }
}

public class RealData implements Data {
 protected final String result;
 public RealData(String para) {
	 //RealData的構造可能很慢,需要使用者等待很久,這裡使用sleep模擬
	 StringBuffer sb=new StringBuffer();
	 for (int i = 0; i < 10; i++) {
		 sb.append(para);
		 try {
			//這裡使用sleep,代替一個很慢的操作過程
			Thread.sleep(100);
		 } catch (InterruptedException e) {
		 }
	}
	result =sb.toString();
 }
 public String getResult() {
	 return result;
 }
}
public class Client {
 public Data request(final String queryStr) {
	final FutureData future = new FutureData();
	new Thread() {
		public void run() {// RealData的構建很慢,
			//所以在單獨的執行緒中進行
			RealData realdata = new RealData(queryStr);
			future.setRealData(realdata);
		}
	}.start();
	return future; // FutureData會被立即返回
 }
}
public static void main(String[] args) {
 Client client = new Client();
 //這裡會立即返回,因為得到的是FutureData而不是RealData
 Data data = client.request("name");
 System.out.println("請求完畢");
 try {
	 //這裡可以用一個sleep代替了對其他業務邏輯的處理
	 //在處理這些業務邏輯的過程中,RealData被建立,從而充分利用了等待時間
	 Thread.sleep(2000);
 } catch (InterruptedException e) {
 }
 //使用真實的資料,資料如果沒準備好,這裡會進行阻塞
 System.out.println("資料 = " + data.getResult());
}

        JDKFuture模式的支

        

            程式碼示例:

public class RealData implements Callable<String> {
	private String para;
	public RealData(String para){
		this.para=para;
	}
	@Override
	public String call() throws Exception {
		StringBuffer sb=new StringBuffer();
		for (int i = 0; i < 10; i++) {
			sb.append(para);
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
			}
		}
		return sb.toString();
	}
}
	public class FutureMain {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		//構造FutureTask
		FutureTask<String> future = new FutureTask<String>(new RealData("a"));
		ExecutorService executor = Executors.newFixedThreadPool(1);
		//執行FutureTask,相當於上例中的 client.request("a") 傳送請求
		//在這裡開啟執行緒進行RealData的call()執行
		executor.submit(future);

		System.out.println("請求完畢");
		try {
			//這裡依然可以做額外的資料操作,這裡使用sleep代替其他業務邏輯的處理
			Thread.sleep(2000);
		} catch (InterruptedException e) {
		}
		//相當於data.getResult (),取得call()方法的返回值
		//如果此時call()方法沒有執行完成,則依然會等待
		System.out.println("資料 = " + future.get());
	}
}
public class FutureMain2 {
 public static void main(String[] args) throws InterruptedException, ExecutionException {

	 ExecutorService executor = Executors.newFixedThreadPool(1);
	 //執行FutureTask,相當於上例中的 client.request("a") 傳送請求
	 //在這裡開啟執行緒進行RealData的call()執行
	 Future<String> future=executor.submit(new RealData("a"));
	 System.out.println("請求完畢");
	 try {
		 //這裡依然可以做額外的資料操作,這裡使用sleep代替其他業務邏輯的處理
		 Thread.sleep(2000);
	 } catch (InterruptedException e) {
	 }
	 //相當於data.getResult (),取得call()方法的返回值
	 //如果此時call()方法沒有執行完成,則依然會等待
	 System.out.println("資料 = " + future.get());
 }
}

生產者消費

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

    主要角色:

    

    類圖: