首先我們來看看單例模式的定義:
單例模式是Java 中最簡單的設計模式之一,屬於建立型模式,它提供了一種創建物件的最佳方式。單例模式涉及到一個單一的類,該類負責創建自己的對象,同時確保只有單個對像被創建。
(推薦教程:java入門教程)
為了保證內存中有且僅有一個對象,避免頻繁的創建對象造成對內存的消耗,讓所有需要呼叫這個物件的地方都使用這一個單例物件。
接下來我們來看看單例模式的類型:
1、懶漢式
#懶漢式指的是需要使用的時候才會去建立該單例對象。
懶漢式單例模式實作:
public class Singleton { private static Singleton singleton; private Singleton(){ } public static Singleton getInstance(){ if (singleton == null) { singleton = new Singleton(); } return singleton; }
對於懶漢式單例實作有一個問題,就是如何確保只建立一個物件?若兩個或多個執行緒同時判斷singleton為空,則會建立多個物件。因此我們需要解決線程安全性問題。
說到執行緒安全想到的就是加鎖了,加鎖無非是在方法或類別物件上加鎖。
//在方法上加锁 public class Singleton { private static Singleton singleton; private Singleton(){} public static synchronized Singleton getInstance() { if (singleton == null) { singleton = new Singleton(); } return singleton; } } //在类对象上加锁 public class Singleton { private static Singleton singleton; private Singleton(){} public static Singleton getInstance() { synchronized(Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } return singleton; } }
這兩個方法,能解決多執行緒同時建立單例物件的問題,但每次取得物件都需要先取得鎖,並發效能差。因此還需要最佳化,最佳化目標為:如果沒有實例化對象,則加鎖創建,如果有實例化對象,則直接返回。
(學習影片推薦:java課程)
對於在方法上加鎖,無論是否存在實例化物件都需要加鎖。故我們需要優化的是在類別物件上加鎖。
//DCL单例模式(Double Check + Lock) public class Singleton { //volatite关键词防止指令重排序,下文介绍 private static volatile Singleton singleton; private Singleton(){} public static Singleton getInstance() { //如果singleton不为空,则直接返回对象,若多个线程发现singleton为空,则进入分支 if (singleton == null) { //多个线程同时争抢一个锁,只有一个线程能成功,其他线程需等待 synchronized(Singleton.class) { //争抢到锁的线程需再次判断singleton是否为空,因为有可能被上个线程实例化了 //若不为空则实例化,后续线程再进入的时候则直接返回该对象 //对于之后所有进入该方法的线程则无需获取锁,直接返回对象 if (singleton == null) { singleton = new Singleton(); } } } return singleton; } }
上述程式碼中加入了volatile關鍵字防止指令重新排序。
2、餓漢式
餓漢式指的是在類別載入時即建立該單例物件。
餓漢式單例模式實作:
public class Singleton { private static final Singleton singleton = new Singleton(); private Singleton(){ } public static Singleton getInstance(){ return singleton; }
總結:
懶漢式:需要時才去實例化對象,在開發中如果對記憶體要求很高即採用懶漢式,在多線程環境下,應該使用DCL單例模式,使用DCL單例模式,解決了並發安全及性能低下的問題,若添加volatile關鍵字還能防止指令重新排序而發生的NPE異常。
餓漢式: 類別載入時就已經實例化對象,如果對記憶體需求不高即採用餓漢式,簡單不易出錯,且沒有任何並發安全與效能問題。
以上是詳細介紹單例模式的詳細內容。更多資訊請關注PHP中文網其他相關文章!