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

首頁 > 編程 > Java > 正文

Java 設計模式 - 單例模式

2019-11-06 07:46:04
字體:
來源:轉載
供稿:網友

基本概念

單例模式具有以下特點:

單例類只能有一個實例。單例類必須自己創建自己的唯一實例。單例類必須給所有其他對象提供這一實例。

它的作用如下:

某些類創建比較頻繁,對于一些大型的對象,這是一筆很大的系統開銷。

省去了 new 操作符,降低了系統內存的使用頻率,減輕 GC 壓力。

有些類如交易所的核心交易引擎,控制著交易流程,如果該類可以創建多個的話,系統完全亂了。(比如一個軍隊出現了多個司令員同時指揮,肯定會亂成一團),所以只有使用單例模式。


實例探究

1.餓漢模式

餓漢模式,指在類被加載時(即類對象被調用前)就完成實例化。

這種方式雖然可以保證單例,并了避免多線程安全問題,但是會提前占用系統資源,效率低下。

public class Singleton { // 持有私有靜態實例,防止被引用 // 對變量直接賦值,時類在被加載時就被實例化 PRivate static Singleton instance =new Singleton(); // 私有構造方法,防止被實例化 private Singleton() { } public static Singleton getInstance() { return instance; }}

2.懶漢模式

為了解決餓漢模式的效率問題,引入了懶漢模式,該模式指的是在類對象被調用時才創建實例。

雖然懶漢模式解決了效率問題,但又帶來線程安全的問題。

當多線程同時調用 getInstance 方法時,都認為 instance 為空,結果就是都新建了類對象。無法保證單例。

public class Singleton { // 不對變量直接賦值,實現延遲加載 private static Singleton instance; private Singleton() { } public static Singleton getInstance() { // 該變量為空時創建 if (instance == null) { instance = new Singleton(); } return instance; }}

2.懶漢模式 - synchronized

普通的懶漢模式既然存在線程安全問題,使用同步關鍵字 synchronized 就方法加鎖能解決。

線程安全的問題是解決了,但是又帶來了新的效率問題。

當多線程調用 getInstance 方法,無論對象是否已被創建,它都會被鎖住。

public class Singleton { private static Singleton instance; private Singleton() { } // 對方法加鎖 public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; }}

3.懶漢模式 - 雙重檢查鎖定

當多線程調用 getInstance 方法,如果對方法加鎖,就會造成效率問題。

而加鎖的主要目的是為了保證創建對象時的線程安全。那么可以縮小同步區域,在新建對象時對其加鎖,存在對象時則不需要加鎖。

public class Singleton { private static Singleton instance; private Singleton() { } public static synchronized Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { // 之所以要再次檢查,因為當線程排序進入同步塊時。 // 第一個線程創建了實例,而后面進入同步塊的線程就必須立即返回 if(instance == null){ instance = new Singleton(); } } } return instance; }}

5.懶漢模式 - volatile

采用雙重檢查鎖定,貌似是解決了已經問題了。但其實不然。原因就于新建類實例時的操作不是原子性的。

// 該語句實際包含了三條指令:// 1.給 Singleton 實例分配內存。// 2.初始化 Singleton 構造器 // 3.將instance 對象指向分配的內存空間(注意到這步 instance 就非null了)。 instance = new Singleton();

java 內存模型中,允許編譯器和處理器對指令進行重排序,但是它會保證程序最終結果會和代碼順序執行結果相同。

所以執行結果可以是 1->2->3,也可是 1->3->2。這種重排序在單線程并不會對線程造成影響,但是在多線程是就會出現問題:

線程1、2 同時訪問同步代碼塊。線程1 線程先進入,線程2 則等待。線程1 創建實例后離開(此時指令執行為 1->3->2)。線程2 進入判斷實例不為空,但是線程對于的 Singleton 初始化構造器還沒完成,導致程序錯誤。

而利用 volatile 修飾變量可以保證它的可見性、有序性,從而讓執行順序為 1->2->3,避免了上述問題。

public class Singleton { // 利用 volatile 關鍵字修飾變量 private volatile static Singleton instance; private Singleton() { } public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if(instance == null){ instance = new Singleton(); } } } return instance; }}

6.懶漢模式 - 靜態內部類

重新分析以上單例模式會帶來的問題:

使用餓漢模式會造成對象提前實例化,占用系統資源。使用懶漢模式會解決了系統資源占用,但會造成線程安全問題。使用 synchronized 、volatile 解決了線程安全問題,但這樣實現的效率其實也不高。

所以需要解決的問題有三:系統資源占用、線程安全、執行效率。

因此這里使用靜態內部類的方式實現,因為:

不提前占用系統資源:當調用 getInstance 時會訪問到 SingletonHolder.instance,此時內部類才被加載并初始化靜態變量,創建實例。

不存在線程安全問題:JVM 內部的機制能夠保證當一個類被加載的時候,這個類的加載過程是線程互斥的。這樣當第一次調用 getInstance 時,JVM能夠保證 instance 只被創建一次,并且會保證把賦值給 instance 的內存初始化完畢。

解決效率問題:只有在 getInstance 第一次被調用時,由 JVM 實現互斥,這樣就解決了低性能問題。

public class Singleton { // 創建靜態內部類 private static class SingletonHolder{ private static Singleton instance= new Singleton(); } private Singleton() { } public static Singleton getInstance() { return SingletonHolder.instance; }}

參考

http://www.cnblogs.com/maowang1991/archive/2013/04/15/3023236.htmlhttp://blog.csdn.net/jason0539/article/details/23297037/
上一篇:Java泛型

下一篇:Java---IO流內存流

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 邯郸市| 沂源县| 高陵县| 衡东县| 基隆市| 曲沃县| 满洲里市| 姚安县| 永川市| 沁阳市| 黄陵县| 攀枝花市| 专栏| 枣强县| 普兰县| 绥棱县| 吐鲁番市| 紫阳县| 鄂托克旗| 名山县| 钦州市| 漳州市| 金塔县| 上饶县| 金沙县| 峡江县| 霍州市| 崇义县| 纳雍县| 伊宁市| 宿州市| 安阳市| 昌乐县| 丹阳市| 临漳县| 华坪县| 永年县| 东丰县| 湖州市| 政和县| 安徽省|