国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

Java 高并發七:并發設計模型詳解

2019-11-26 13:51:00
字體:
來源:轉載
供稿:網友

1. 什么是設計模式

在軟件工程中,設計模式(design pattern)是對軟件設計中普遍存在(反復出現)的各種問題 ,所提出的解決方案。這個術語是由埃里希?伽瑪(Erich Gamma)等人在1990年代從建筑設計領 域引入到計算機科學的。

著名的4人幫: Erich Gamma,Richard Helm, Ralph Johnson ,John Vlissides (Gof)

《設計模式:可復用面向對象軟件的基礎》收錄23種模式

2. 單例模式

單例對象的類必須保證只有一個實例存在。許多時候整個系統只需要擁有一個的全局對象,這樣有利于我們協調系統整體的行為

比如:全局信息配置

單例模式最簡單的實現:

public class Singleton { private Singleton() { System.out.println("Singleton is create"); } private static Singleton instance = new Singleton(); public static Singleton getInstance() { return instance; }}

由私有構造方法和static來確定唯一性。

缺點:何時產生實例 不好控制

雖然我們知道,在類Singleton第一次被加載的時候,就產生了一個實例。

但是如果這個類中有其他屬性

public class Singleton { public static int STATUS=1;  private Singleton() { System.out.println("Singleton is create"); } private static Singleton instance = new Singleton(); public static Singleton getInstance() { return instance; }}

當使用

System.out.println(Singleton.STATUS);

這個實例就被產生了。也許此時你并不希望產生這個實例。

如果系統特別在意這個問題,這種單例的實現方法就不太好。

第二種單例模式的解決方式:

public class Singleton { private Singleton() { System.out.println("Singleton is create"); } private static Singleton instance = null; public static synchronized Singleton getInstance() { if (instance == null) instance = new Singleton(); return instance; }}

讓instance只有在調用getInstance()方式時被創建,并且通過synchronized來確保線程安全。
這樣就控制了何時創建實例。

這種方法是延遲加載的典型。

但是有一個問題就是,在高并發的場景下性能會有影響,雖然只有一個判斷就return了,但是在并發量很高的情況下,或多或少都會有點影響,因為都要去拿synchronized的鎖。

為了高效,有了第三種方式:

public class StaticSingleton { private StaticSingleton(){  System.out.println("StaticSingleton is create"); } private static class SingletonHolder { private static StaticSingleton instance = new StaticSingleton(); } public static StaticSingleton getInstance() { return SingletonHolder.instance; }}

由于加載一個類時,其內部類不會被加載。這樣保證了只有調用getInstance()時才會產生實例,控制了生成實例的時間,實現了延遲加載。

并且去掉了synchronized,讓性能更優,用static來確保唯一性。

3. 不變模式

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

不變模式不需要同步

創建一個不變的類:

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; }}

Java中不變的模式的案例有:

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 

4. Future模式

核心思想是異步調用

非異步:

異步:

第一次的call_return由于任務還沒完成,所以返回的是一個空的。

但是這個返回類似于購物中的訂單,將來可以根據這個訂單來得到一個結果。

所以這個Future模式意思就是,“未來”可以得到,就是指這個訂單或者說是契約,“承諾”未來就會給結果。

Future模式簡單的實現:

調用者得到的是一個Data,一開始可能是一個FutureData,因為RealData構建很慢。在未來的某個時間,可以通過FutureData來得到RealData。

代碼實現:


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()); }

JDK中也有多Future模式的支持:


接下來使用JDK提供的類和方法來實現剛剛的代碼:

import java.util.concurrent.Callable;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(); }}
import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.FutureTask;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()); }}

這里要注意的是FutureTask是即具有 Future功能又具有Runnable功能的類。所以又可以運行,最后還能get。
當然如果在調用到future.get()時,真實數據還沒準備好,仍然會產生阻塞狀況,直到數據準備完成。

當然還有更加簡便的方式:

import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;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()); }}

由于Callable是有返回值的,可以直接返回future對象。

5. 生產者消費者

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

以前寫過一篇用Java來實現生產者消費者的多種方法,這里就不多闡述了。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 和政县| 绥滨县| 工布江达县| 乌兰县| 普陀区| 贺州市| 沧州市| 南康市| 岫岩| 保靖县| 扎兰屯市| 行唐县| 凭祥市| 治多县| 榆社县| 丹阳市| 武宣县| 东乡| 体育| 左贡县| 电白县| 赣榆县| 绥德县| 庐江县| 绥化市| 苏州市| 池州市| 阿瓦提县| 大关县| 阜阳市| 贵南县| 台前县| 黔西县| 内丘县| 本溪市| 宁夏| 双鸭山市| 鄂温| 年辖:市辖区| 赤壁市| 平潭县|