程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java 高並發七:並發設計模子詳解

Java 高並發七:並發設計模子詳解

編輯:關於JAVA

Java 高並發七:並發設計模子詳解。本站提示廣大學習愛好者:(Java 高並發七:並發設計模子詳解)文章只能為提供參考,不一定能成為您想要的結果。以下是Java 高並發七:並發設計模子詳解正文


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來完成臨盆者花費者的多種辦法,這裡就不多論述了。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved