<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
所謂類的單例設計模式,就是採取一定的方法保證在整個的軟體系統中,對某個類只能存在一個物件範例,並且該類只提供一個取得其物件範例的方法(靜態方法)。
比如Hibernate的 SessionFactory,它充當資料儲存源的代理,並負責建立Session物件。SessionFactory並不是輕量級的,一般情況下,一個專案通常只需要一個SessionFactory就夠,這是就會使用到單例模式。
這篇文章中,我將給出單例模式的七種寫法:
以上七種寫法中標紅的是推薦使用的,如果說你能保證你的程式中單例類的範例一定會使用到,那麼餓漢式也是推薦使用的。
package com.szh.singleton.type1; /** * 餓漢式(靜態變數) */ class Singleton { // 本類內部建立物件範例 private static final Singleton INSTANCE = new Singleton(); // 構造方法私有化, 防止外部new物件 private Singleton() {} // 提供一個公有的靜態方法,返回範例物件 public static Singleton getInstance() { return INSTANCE; } } public class SingletonTest01 { public static void main(String[] args) { Singleton singleton1 = Singleton.getInstance(); Singleton singleton2 = Singleton.getInstance(); System.out.println(singleton1 == singleton2); System.out.println("singleton1的hashCode = " + singleton1.hashCode()); System.out.println("singleton2的hashCode = " + singleton2.hashCode()); } }
優缺點說明:
優點: 這種寫法比較簡單,就是在類裝載的時候就完成範例化。避免了執行緒同步問題。
缺點: 在類裝載的時候就完成範例化,沒有達到Lazy Loading 的效果。如果從始至終從未使用過這個範例,則會造成記憶體的浪費。
這種方式基於classloder機制避免了多執行緒的同步問題,不過,instance在類裝載時就範例化,在單例模式中大多數都是呼叫getInstance方法,但是導致類裝載的原因有很多種,因此不能確定有其他的方式(或者其他的靜態方法)導致類裝載,這時候初始化 instance就沒有達到lazy loading 的效果。
結論:這種單例模式可用,可能造成記憶體浪費。
package com.szh.singleton.type2; /** * 餓漢式(靜態程式碼塊) */ class Singleton { private static final Singleton INSTANCE; // 構造方法私有化, 防止外部new物件 private Singleton() {} // 靜態程式碼塊, 完成物件的範例建立 static { INSTANCE = new Singleton(); } // 提供一個公有的靜態方法,返回範例物件 public static Singleton getInstance() { return INSTANCE; } } public class SingletonTest02 { public static void main(String[] args) { Singleton singleton1 = Singleton.getInstance(); Singleton singleton2 = Singleton.getInstance(); System.out.println(singleton1 == singleton2); System.out.println("singleton1的hashCode = " + singleton1.hashCode()); System.out.println("singleton2的hashCode = " + singleton2.hashCode()); } }
優缺點說明:
這種方式和第一種方式其實類似,只不過將類範例化的過程放在了靜態程式碼塊中,也是在類裝載的時候,就執行靜態程式碼塊中的程式碼,初始化類的範例。優缺點和上面是一樣的。
結論:這種單例模式可用,但是可能造成記憶體浪費。
package com.szh.singleton.type3; import java.util.Objects; /** * 懶漢式(執行緒不安全) */ class Singleton { private static Singleton instance; // 構造方法私有化, 防止外部new物件 private Singleton() {} // 提供一個公有的靜態方法,返回範例物件 public static Singleton getInstance() { if (Objects.isNull(instance)) { instance = new Singleton(); } return instance; } } public class SingletonTest03 { public static void main(String[] args) { Singleton singleton1 = Singleton.getInstance(); Singleton singleton2 = Singleton.getInstance(); System.out.println(singleton1 == singleton2); System.out.println("singleton1的hashCode = " + singleton1.hashCode()); System.out.println("singleton2的hashCode = " + singleton2.hashCode()); } }
優缺點說明:
起到了Lazy Loading 的效果,但是隻能在單執行緒下使用。
如果在多執行緒下,一個執行緒進入了if (singleton== null)判斷語句塊,還未來得及往下執行,另一個執行緒也通過了這個判斷語句,這時便會產生多個範例。所以在多執行緒環境下不可使用這種方式。
結論: 在實際開發中,不要使用這種方式。
package com.szh.singleton.type4; import java.util.Objects; /** * 懶漢式(執行緒安全, 雙重校驗鎖) */ class Singleton { private static Singleton instance; // 構造方法私有化, 防止外部new物件 private Singleton() {} // 提供一個公有的靜態方法,返回範例物件 public static synchronized Singleton getInstance() { if (Objects.isNull(instance)) { instance = new Singleton(); } return instance; } } public class SingletonTest04 { public static void main(String[] args) { Singleton singleton1 = Singleton.getInstance(); Singleton singleton2 = Singleton.getInstance(); System.out.println(singleton1 == singleton2); System.out.println("singleton1的hashCode = " + singleton1.hashCode()); System.out.println("singleton2的hashCode = " + singleton2.hashCode()); } }
優缺點說明:
解決了執行緒安全問題。
效率太低了,每個執行緒在想獲得類的範例時候,執行getInstance()方法都要進行同步。而其實這個方法只執行一次範例化程式碼就夠了,後面的想獲得該類範例,直接return就行了。方法進行同步效率太低。
結論: 在實際開發中,不推薦使用這種方式。
package com.szh.singleton.type5; import java.util.Objects; /** * 懶漢式(執行緒安全) */ class Singleton { private static volatile Singleton instance; // 構造方法私有化, 防止外部new物件 private Singleton() {} // 提供一個公有的靜態方法,返回範例物件 public static Singleton getInstance() { if (Objects.isNull(instance)) { synchronized (Singleton.class) { if (Objects.isNull(instance)) { instance = new Singleton(); } } } return instance; } } public class SingletonTest05 { public static void main(String[] args) { Singleton singleton1 = Singleton.getInstance(); Singleton singleton2 = Singleton.getInstance(); System.out.println(singleton1 == singleton2); System.out.println("singleton1的hashCode = " + singleton1.hashCode()); System.out.println("singleton2的hashCode = " + singleton2.hashCode()); } }
優缺點說明:
Double-Check概念是多執行緒開發中常使用到的,如程式碼中所示,我們進行了兩次if (singleton ==- null)檢查,這樣就可以保證執行緒安全了。
這樣,範例化程式碼只用執行一次,後面再次存取時,判斷if(singleton == null),直接return 範例化物件,也避免的反覆進行方法同步。
執行緒安全;延遲載入;效率較高。
結論: 在實際開發中,推薦使用這種單例設計模式。
package com.szh.singleton.type6; import java.util.Objects; /** * 靜態內部類 */ class Singleton { // 構造方法私有化, 防止外部new物件 private Singleton() {} // 定義靜態內部類 private static class SingletonInstance { private static final Singleton INSTANCE = new Singleton(); } // 提供一個公有的靜態方法,返回靜態內部類中的範例物件 public static Singleton getInstance() { return SingletonInstance.INSTANCE; } } public class SingletonTest06 { public static void main(String[] args) { Singleton singleton1 = Singleton.getInstance(); Singleton singleton2 = Singleton.getInstance(); System.out.println(singleton1 == singleton2); System.out.println("singleton1的hashCode = " + singleton1.hashCode()); System.out.println("singleton2的hashCode = " + singleton2.hashCode()); } }
優缺點說明:
這種方式採用了類裝載機制來保證初始化範例時只有一個執行緒。
靜態內部類方式在Singleton類被裝載時並不會立即範例化,而是在需要範例化時,呼叫getInstance方法,才會裝載SingletonInstance類,從而完成Singleton的範例化。
類的靜態屬性只會在第一次載入類的時候初始化,所以在這裡,JVM幫助我們保證了執行緒的安全性,在類進行初始化時,別的執行緒是無法進入的。
優點: 避免了執行緒不安全,利用靜態內部類特點實現延遲載入,效率高。
結論: 推薦使用。
package com.szh.singleton.type7; /** * 列舉 */ enum Singleton { INSTANCE; } public class SingletonTest07 { public static void main(String[] args) { Singleton singleton1 = Singleton.INSTANCE; Singleton singleton2 = Singleton.INSTANCE; System.out.println(singleton1 == singleton2); System.out.println("singleton1的hashCode = " + singleton1.hashCode()); System.out.println("singleton2的hashCode = " + singleton2.hashCode()); } }
優缺點說明:
藉助JDK1.5中新增的列舉來實現單例模式。不僅能避免多執行緒同步問題,而且還能防止反序列化重新建立新的物件。
這種方式是Effective Java作者Josh Bloch提倡的方式。
結論: 推薦使用。
我們可以看一下有一個類叫 Runtime,位於java.lang包下的。
從這個類的原始碼中可以看到,它首先是建立了一個私有的本類範例物件,然後最下面就是構造方法私有化,中間的公共方法則是提供給外部的,外部類可以通過這個方法來獲取到Runtime這個類的範例物件。這不就是我們上面所說的單例模式嗎?這裡它採用的是餓漢式寫法。
單例模式保證了系統記憶體中該類只存在一個物件,節省了系統資源,對於一些需要頻繁建立銷燬的物件,使用單例模式可以提高系統效能。
當想範例化一個單例類的時候,必須要記住使用相應的獲取物件的方法,而不是使用new。
單例模式使用的場景:需要頻繁的進行建立和銷燬的物件、建立物件時耗時過多或耗費資源過多(即: 重量級物件),但又經常用到的物件、工具類物件、頻繁存取資料庫或檔案的物件(比如資料來源、session 工廠等)。
以上就是java程式設計建立型設計模式單例模式的七種寫法範例詳解的詳細內容,更多關於java建立型設計模式單例模式的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45