八種寫(xiě)法:
1)餓漢式(靜態(tài)常量)
2)餓漢式(靜態(tài)代碼塊)
3)懶漢式(線程不安全)
4)懶漢式(線程安全紊婉,同步方法)
5)懶漢式(線程安全辕宏,同步代碼塊)
6)雙重檢查
7)靜態(tài)內(nèi)部類
8)枚舉
餓漢式:在類加載的時(shí)候就創(chuàng)建實(shí)例對(duì)象,沒(méi)有節(jié)約內(nèi)存宇智。
懶漢式:在使用的時(shí)候才去創(chuàng)建實(shí)例對(duì)象蔓搞,節(jié)省了內(nèi)存。
---------------------------------------------------------------
1)餓漢式(靜態(tài)常量)
public class SingletonOne {
private SingletonOne(){}
private final static SingletonOne instance = new SingletonOne();
public static SingletonOne getInstance() {
return instance;
}
}
優(yōu)點(diǎn):寫(xiě)法簡(jiǎn)單随橘,在類加載的時(shí)候就完成了實(shí)例化喂分。避免了線程同步問(wèn)題。
缺點(diǎn):在類加載的時(shí)候就完成了實(shí)例化机蔗,沒(méi)有達(dá)到懶加載的效果蒲祈。
android中的application中可以使用此種方式。(實(shí)例化時(shí)要在onCreate()方法中進(jìn)行)
---------------------------------------------------------------
2)餓漢式(靜態(tài)代碼塊)
public class SingletonTwo {
private SingletonTwo(){}
private static SingletonTwo instance;
static {
instance = new SingletonTwo();
}
public static SingletonTwo getInstance() {
return instance;
}
}
優(yōu)缺點(diǎn)同第一種寫(xiě)法
---------------------------------------------------------------
3)懶漢式(線程不安全)
public class SingletonThree {
private static SingletonThree instance;
private SingletonThree(){}
/**
* 只有在用的時(shí)候才調(diào)用這個(gè)方法萝嘁,才會(huì)創(chuàng)建實(shí)例對(duì)象
*/
public static SingletonThree getInstance() {
if(instance == null) {
// 多線程情景下梆掸,會(huì)有多個(gè)線程執(zhí)行到此處
instance = new SingletonThree();
}
return instance;
}
}
優(yōu)點(diǎn):懶加載
缺點(diǎn):線程不安全
可以在確保是單線程的場(chǎng)景下使用
---------------------------------------------------------------
4)懶漢式(線程安全,但是速度慢)
public class SingletonFour {
private static SingletonFour instance;
private SingletonFour(){}
/**
* 加入synchronized后牙言,每次調(diào)用都會(huì)同步酸钦,所以速度慢
*/
public static synchronized SingletonFour getInstance() {
if(instance == null) {
instance = new SingletonFour();
}
return instance;
}
}
優(yōu)點(diǎn):懶加載,線程安全
缺點(diǎn):速度慢
不推薦使用
---------------------------------------------------------------
5)懶漢式(線程不安全咱枉,同步代碼塊)
public class SingletonFive {
private static SingletonFive instance;
private SingletonFive(){}
public static SingletonFive getInstance() {
if(instance == null) {
// 多線程情景下卑硫,還是會(huì)有多個(gè)線程進(jìn)入到這行,只不過(guò)會(huì)并行而已
synchronized (SingletonFive.class) {
instance = new SingletonFive();
}
}
return instance;
}
}
優(yōu)點(diǎn):懶加載
缺點(diǎn):線程不安全
不推薦使用
---------------------------------------------------------------
6)雙重檢查
public class SingleonSix {
private static volatile SingleonSix instance;
private SingleonSix(){}
public static SingleonSix getInstance() {
if(instance == null) {
// 多線程場(chǎng)景下蚕断,會(huì)有多個(gè)線程進(jìn)入到這行欢伏,但是下一行只有第一個(gè)能進(jìn)去
synchronized (SingleonSix.class) {
if(instance == null) {
instance = new SingleonSix();
}
}
}
return instance;
}
}
優(yōu)點(diǎn):懶加載,線程安全亿乳,速度較快
推薦使用
---------------------------------------------------------------
7)靜態(tài)內(nèi)部類
public class SingleonSeven {
private SingleonSeven(){}
private static class SingletonInstance {
private static final SingleonSeven INSTANCE = new SingleonSeven();
}
public static SingleonSeven getInstance() {
return SingletonInstance.INSTANCE;
}
}
說(shuō)明:采用類加載的機(jī)制來(lái)保證初始化實(shí)例時(shí)只有一個(gè)線程硝拧。靜態(tài)內(nèi)部類SingletonInstance 在類SingleonSeven裝載的時(shí)候不會(huì)立即實(shí)例化。只有調(diào)用getInstance()方法時(shí)才會(huì)實(shí)例化葛假。類的靜態(tài)屬性只有在第一次加載類的時(shí)候才初始化障陶。這樣JVM保證了線程的安全,在類進(jìn)行初始化時(shí)桐款,別的線程是無(wú)法進(jìn)入的咸这。
線程安全,懶加載魔眨,推薦使用
---------------------------------------------------------------
8)枚舉
public enum SingleonEight {
INSTANCE;
public void sayHello() {
System.out.println("hello");
}
}
說(shuō)明: 枚舉是確保單例的媳维。
---------------------------------------------------------------
jdk源碼中的單例使用舉例:Runtime .java
public class Runtime {
private static Runtime currentRuntime = new Runtime();
/**
* Returns the runtime object associated with the current Java application.
* Most of the methods of class <code>Runtime</code> are instance
* methods and must be invoked with respect to the current runtime object.
*
* @return the <code>Runtime</code> object associated with the current
* Java application.
*/
public static Runtime getRuntime() {
return currentRuntime;
}
/** Don't let anyone else instantiate this class */
private Runtime() {}
......
}
Android源碼中的使用:WindowManagerService .java
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
//......
private static WindowManagerService sInstance;
static WindowManagerService getInstance() {
return sInstance;
}
public static WindowManagerService main(final Context context, final InputManagerService im,
final boolean haveInputMethods, final boolean showBootMsgs, final boolean onlyCore,
WindowManagerPolicy policy) {
DisplayThread.getHandler().runWithScissors(() ->
sInstance = new WindowManagerService(context, im, haveInputMethods, showBootMsgs,
onlyCore, policy), 0);
return sInstance;
}
//......
}