確保某一個類只有一個實例,並且自行實例化並向整個系統提供這個實例。數據庫
當對象須要消耗的資源過多(如訪問Io、數據庫等),避免產生多個對象消耗過多的資源,或者某種類型的對象只應該有且只有一個。安全
依靠靜態對象的初始化實現單例bash
public class Singleton{
private static Singleton mInstance = new Singleton();
private Singleton() {}
public static synchronized Singleton getInstance(){
return mInstance;
}
}
複製代碼
第一次調用getInstance()後,單例對象就會被實例化。但每次調用getInstance()方法時都須要進行同步,會形成沒必要要的消耗。
對於不頻繁調用getInstance()的狀況下,能夠適用。ui
public class Singleton{
private static Singleton mInstance;
private Singleton() {}
public static synchronized Singleton getInstance(){
if( mInstance == null){
mInstance = new Singleton();
}
return mInstance;
}
}
複製代碼
public class Singleton{
private volatile static Singleton mInstance;
private Singleton() {}
public static Singleton getInstance(){
if( mInstance == null){
synchronized(Singleton.class){
if( mInstance == null){
mInstance = new Singleton();
}
}
}
return mInstance;
}
}
複製代碼
進行兩次判空,第一次判斷主要避免沒必要要的同步,第二次判斷主要爲了在同步狀況下確認單例仍爲空時,進行初始化。
spa
volatile關鍵字的做用:
一、防止重排序
new對象時,會進行三件事件:
(1)、給Singleton的實例分配內存;
(2)、調用Singleton()的構造方法,初始化成員變量。
(3)、將mInstance對象指向分配的內存空間。
而在JVM中(2)和(3)的順序是沒法被保證的,只能經過volalite保證其有序性。
線程
二、保證線程的可見性。
code
依靠靜態內部類被使用時才被JVM加載的原理。對象
public class Singleton{
private Singleton{}
public static Singleton getInstance(){
return SingletonHolder.mInstance;
}
//靜態內部類
private static class SingletonHolder{
private static final Singleton mInstance = new Singleton();
}
}
複製代碼
靜態內部類和非靜態內部類加載時機的區別:
排序
非靜態內部類,必定須要外部類實例化後纔會被加載。
事件
靜態內部類的加載不須要依附外部類,在使用時才加載進。
將多種單例類型注入到一個統一的管理類中,使用時根據key獲取對應的單例對象。
public class SingletonManager{
private static Map<String,Object> objMap = new HashMap<String,Object>();
private SingletonManager{}
public static void registerService(String key,Object instance){
if(!object.containsKey(key)){
objMap.put(key,instance);
}
}
public static Object getService(String key){
return objMap.get(key);
}
}
複製代碼
枚舉類型能夠定義本身的方法和本身的變量,並且枚舉實例的建立是線程安全的,而且任何狀況下都是單例。
public enum SingletonEnum{
INSTANCE;
public void doSomething(){
System.out.println("do ");
}
}
複製代碼