注: 場景和例子出自github的設計模式。傳送門:https://github.com/iluwatar/java-design-patterns/tree/master/singleton
意圖:
單例模式即使為了確保一個類只有一個實例,並提供一個全局訪問點。
場景:
世界上只有一座象牙塔可以讓巫師學習魔法,所有巫師都來到這座象牙塔進行修習。那么象牙塔就這里可以理解為單例。簡單的來說就是只創建一個類的一個對象,這個象牙塔就可以理解為唯一對象。
實現:
想更好的理解單例模式,最好先了解一下java中的關鍵字Static。傳送門:http://www.cnblogs.com/ahangBlogs/p/7719330.html
talk is cheap,show me the code.........................................................................................................................................................................................................................................(分割線)
列舉幾種單例模式的實現方法:
一:
package Singleton; public final class IvoryTower { private IvoryTower(){} private static final IvoryTower Instance=new IvoryTower(); public static IvoryTower GetInstance(){ return Instance; } }
二:ThreadSafeLazyLoaded
package Singleton; public final class ThreadSafeLazyLoadedIvoryTower { private static ThreadSafeLazyLoadedIvoryTower Instance; private ThreadSafeLazyLoadedIvoryTower(){ if(Instance!=null){ throw new IllegalStateException("Already initialized."); } } public static ThreadSafeLazyLoadedIvoryTower GetInstance(){ if(Instance==null){ Instance=new ThreadSafeLazyLoadedIvoryTower(); } return Instance; } }
三:線程安全雙重鎖檢查
package Singleton; public class ThreadSafeDoubleCheckLocking { private static ThreadSafeDoubleCheckLocking instance; private ThreadSafeDoubleCheckLocking(){ if(instance!=null){ throw new IllegalStateException("Already instance!"); } } public static ThreadSafeDoubleCheckLocking GetInstance(){ //使用局部變量可提高25%性能。 出自effectice java th2.. 簡單來說就是局部變量保存在堆棧中....
ThreadSafeDoubleCheckLocking result=instance; //檢查單例模式的實力是否初始化,如果已經初始化就直接返回實例,沒有初始化就往下走
if(result==null){ //實例沒有初始化,不過我們不能確保在這個時間段其他線程是否初始化了這個實例, 所以為了確保正確我們得鎖住一個對象來互相排斥。 synchronized (ThreadSafeDoubleCheckLocking.class) { //再次將是實例賦值給局部變量,這時候當前線程無法進入該鎖空間,如果已經初始化我們返還實例 result=instance; if(result==null){ //進入該if中,即沒有在其他線程中進行初始化。那么我們可以安全的創建一個實例作為我們的單例實例。 instance=result=new ThreadSafeDoubleCheckLocking(); } } } return result; } }
四:
package Singleton; public enum EnumIvoryTower { INSTANCE; @Override public String toString(){ return getDeclaringClass().getCanonicalName() + "@" + hashCode(); } }
適用性:
使用Singleton模式
- 必須只有一個類的實例,並且必須可以從知名訪問點訪問客戶端
- 當唯一的實例應該通過子類來擴展時,客戶端應該能夠使用擴展實例而不修改它們的代
缺點:
- 違反單一責任原則(SRP)通過控制自己的創作和生命周期。
- 鼓勵使用全局共享實例,以防止該對象使用的對象和資源被釋放。
- 創建緊密耦合的代碼。Singleton的客戶變得難以測試。