單例模式確保某個類只有1個實例,而且實例并向全部系統(tǒng)提供這個實例。
單例模式的3個特點:
單例模式中還存在著兩種設(shè)計模式
package com.designpattern.singleton; /** * Created by Administrator on 2016/9/20. */ public class EagerSingleton { private static final EagerSingleton eagerSingleton = new EagerSingleton(); private EagerSingleton(){ } public static EagerSingleton getInstance(){ return eagerSingleton; } public static void main(String args[]){ EagerSingleton eagerSingleton1 = EagerSingleton.getInstance(); EagerSingleton eagerSingleton2 = EagerSingleton.getInstance(); System.out.println(eagerSingleton1==eagerSingleton2); } }
這類模式下線程是安全的,不會出現(xiàn)延遲加載而致使產(chǎn)生不同的實例對象。上面是采取靜態(tài)常量的情勢,代碼也能夠使用靜態(tài)代碼塊的情勢。靜態(tài)代碼塊的情勢以下:
package com.designpattern.singleton; /** * Created by Administrator on 2016/9/20. */ public class EagerSingleton { private static final EagerSingleton eagerSingleton; static { eagerSingleton = new EagerSingleton(); } private EagerSingleton(){ } public static EagerSingleton getInstance(){ return eagerSingleton; } public static void main(String args[]){ EagerSingleton eagerSingleton1 = EagerSingleton.getInstance(); EagerSingleton eagerSingleton2 = EagerSingleton.getInstance(); System.out.println(eagerSingleton1==eagerSingleton2); } }
懶漢式的單例模式是線程不安全的,如果在多線程下,1個線程進入了if (lazySingleton == null)判斷語句塊,還未來得及往下履行,另外一個線程也通過了這個判斷語句,這時候便會產(chǎn)生多個實例。所以在多線程環(huán)境下不可以使用這類方式。
package com.designpattern.singleton; /** * Created by Administrator on 2016/9/20. */ class LazySingleton { private static LazySingleton lazySingleton = null; private LazySingleton(){ } public static LazySingleton getInstance(){ if(lazySingleton == null){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } lazySingleton = new LazySingleton(); } return lazySingleton; } } class LazySigletonThread implements Runnable{ @Override public void run() { System.out.println(LazySingleton.getInstance()); } public static void main(String[] args) { LazySigletonThread lazySigletonThread1 = new LazySigletonThread(); LazySigletonThread lazySigletonThread2 = new LazySigletonThread(); Thread thread1 = new Thread(lazySigletonThread1); Thread thread2 = new Thread(lazySigletonThread2); thread1.start(); thread2.start(); } }
履行結(jié)果會出現(xiàn)不同的實例對象,這樣單例模式就失去存在的意義。
com.designpattern.singleton.LazySingleton@24189895 com.designpattern.singleton.LazySingleton@2e24a61e
但是如果在給getInstance()
方法加上synchronized
機制,這樣就不會出現(xiàn)兩個不同的實體類對象了。
synchronized public static LazySingleton getInstance(){ if(lazySingleton == null){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } lazySingleton = new LazySingleton(); } return lazySingleton; }
public class Singleton { private Singleton() {} private static class SingletonInstance { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { return SingletonInstance.INSTANCE; } }
這類方式跟餓漢式方式采取的機制類似,但又有不同。二者都是采取了類裝載的機制來保證初始化實例時只有1個線程。不同的地方在餓漢式方式是只要Singleton類被裝載就會實例化,沒有Lazy-Loading的作用,而靜態(tài)內(nèi)部類方式在Singleton類被裝載時其實不會立即實例化,而是在需要實例化時,調(diào)用getInstance方法,才會裝載SingletonInstance類,從而完成Singleton的實例化。
類的靜態(tài)屬性只會在第1次加載類的時候初始化,所以在這里,JVM幫助我們保證了線程的安全性,在類進行初始化時,別的線程是沒法進入的。