1.餓漢式
實(shí)現(xiàn)代碼:
public class MySingleton {
??// 1.餓漢式
??private static MySingleton singleton = new??MySingleton();
??private MySingleton() {
??}
??public static MySingleton getInstance() {
????return singleton;
??}
}
開(kāi)啟多線程進(jìn)行測(cè)試:
public class SingletonMain extends Thread {
??@Override
??public void run() {
?????System.out.println(MySingleton.getInstance().hashCode());
??}
??public static void main(String[] args) {
????// 創(chuàng)建多線程汰扭,一起執(zhí)行看是否生成同一對(duì)象
????SingletonMain th1 = new SingletonMain();
????SingletonMain th2 = new SingletonMain();
????SingletonMain th3 = new SingletonMain();
????th1.start();
????th2.start();
????th3.start();
??}
}
結(jié)果:
477037219
477037219
477037219
結(jié)論:hashCode值一致口叙,說(shuō)明是同一對(duì)象止吐,餓漢式單例模式線程安全
2.懶漢式
實(shí)現(xiàn)代碼
public class MySingleton {
??// 2.懶漢式
??private static MySingleton instance = null;
??private MySingleton() {
??}
??public static MySingleton getInstance() throws??InterruptedException {
????if (instance == null) {
??????// 創(chuàng)建實(shí)例之前可能會(huì)有一些準(zhǔn)備性的耗時(shí)工作
??????Thread.sleep(300);
??????instance = new MySingleton();
????}
????return instance;
??}
}
開(kāi)啟多線程進(jìn)行測(cè)試算柳,
public class SingletonMain extends Thread {
??@Override
??public void run() {
????try {
???????System.out.println(MySingleton.getInstance().hashCode());
????} catch (InterruptedException e) {
??????e.printStackTrace();
????}
??}
??public static void main(String[] args) {
????// 創(chuàng)建多線程惨好,一起執(zhí)行看是否生成同一對(duì)象
????SingletonMain th1 = new SingletonMain();
????SingletonMain th2 = new SingletonMain();
????SingletonMain th3 = new SingletonMain();
????th1.start();
????th2.start();
????th3.start();
??}
}
結(jié)果
1891072390
1139700714
477037219
結(jié)論:
不同線程輸出的hashCode值不一致,對(duì)象不同竖配,懶漢式單例模式線程不安全哨鸭。
造成不安全的原因:多個(gè)線程在進(jìn)入getInstance方法時(shí),都并沒(méi)有對(duì)象創(chuàng)建出來(lái)粥谬,導(dǎo)致所有線程都符合(instance == null)的條件肛根,導(dǎo)致對(duì)象被重復(fù)創(chuàng)建,不構(gòu)成單例的前提
2-01.?懶漢式改良版-靜態(tài)同步函數(shù)實(shí)現(xiàn)
實(shí)現(xiàn)代碼漏策,增加synchronized關(guān)鍵詞派哲,靜態(tài)同步函數(shù)實(shí)現(xiàn)線程安全
public class MySingleton {
??// 2.懶漢式
??private static MySingleton instance = null;
??private MySingleton() {
??}
??public static synchronized MySingleton getInstance()??throws InterruptedException {
????if (instance == null) {
??????// 創(chuàng)建實(shí)例之前可能會(huì)有一些準(zhǔn)備性的耗時(shí)工作
??????Thread.sleep(300);
??????instance = new MySingleton();
????}
????return instance;
??}
}
結(jié)果
1891072390
1891072390
1891072390
結(jié)論:
靜態(tài)同步函數(shù)可以實(shí)現(xiàn)懶漢式單例模式的線程安全,但是將一整個(gè)方法都進(jìn)行加鎖掺喻,會(huì)導(dǎo)致此方法的運(yùn)行效率降低芭届,繼續(xù)考慮其他方式進(jìn)行改良
2-02.??懶漢式改良版-同步代碼塊實(shí)現(xiàn)
實(shí)現(xiàn)代碼:增加synchronized關(guān)鍵詞,對(duì)指定代碼塊加鎖感耙,可以大大的提高整個(gè)方法的執(zhí)行效率褂乍,下面使用同步代碼塊實(shí)現(xiàn)
public class MySingleton {
??// 2.懶漢式
??private static MySingleton instance = null;
??private MySingleton() {
??}
??public static MySingleton getInstance() throws??InterruptedException {
????if (instance == null) {
??????// 創(chuàng)建實(shí)例之前可能會(huì)有一些準(zhǔn)備性的耗時(shí)工作
??????Thread.sleep(300);
??????synchronized (MySingleton.class) {
????????instance = new MySingleton();
??????}
????}
????return instance;
??}
}
結(jié)果
1891072390
756680587
1994444141
結(jié)論:目前此種調(diào)整方式還不能達(dá)到線程安全,繼續(xù)改良
雙檢查鎖機(jī)制
實(shí)現(xiàn)代碼
public class MySingleton {
??// 2.懶漢式
??private static MySingleton instance = null;
??private MySingleton() {
??}
??public static MySingleton getInstance() throws??InterruptedException {
????if (instance == null) {
??????// 創(chuàng)建實(shí)例之前可能會(huì)有一些準(zhǔn)備性的耗時(shí)工作
??????Thread.sleep(300);
??????synchronized (MySingleton.class) {
????????if (instance == null) {
??????????instance = new MySingleton();
????????}
??????}
????}
????return instance;
??}
}
結(jié)果:
1994444141
1994444141
1994444141
結(jié)論:
雙檢查鎖機(jī)制可以實(shí)現(xiàn)懶漢式單例模式的線程安全即硼,而且這種方式的效率相對(duì)于第一種來(lái)說(shuō)是比較高的
3.靜態(tài)內(nèi)置類實(shí)現(xiàn)單例模式
實(shí)現(xiàn)代碼
public class MySingleton {
??private static class MySingletonHandler {
????private static MySingleton singleon = new??MySingleton();
??}
??public static MySingleton getInstance() {
????return MySingletonHandler.singleon;
??}
}
開(kāi)啟多線程測(cè)試
public class SingletonMain extends Thread {
??@Override
??public void run() {
?????System.out.println(MySingleton.getInstance().hashCode());
??}
??public static void main(String[] args) {
????// 創(chuàng)建多線程树叽,一起執(zhí)行看是否生成同一對(duì)象
????SingletonMain th1 = new SingletonMain();
????SingletonMain th2 = new SingletonMain();
????SingletonMain th3 = new SingletonMain();
????th1.start();
????th2.start();
????th3.start();
??}
}
結(jié)果
1740545285
1740545285
1740545285
結(jié)論:
靜態(tài)內(nèi)置類實(shí)現(xiàn)單例模式是線程安全的
4.靜態(tài)代碼塊實(shí)現(xiàn)單例模式
實(shí)現(xiàn)代碼:靜態(tài)代碼塊中的代碼在使用類的時(shí)候就已經(jīng)執(zhí)行了,所以可以應(yīng)用靜態(tài)代碼塊的這個(gè)特性的實(shí)現(xiàn)單例設(shè)計(jì)模式谦絮。
public class MySingleton {
??// 使用靜態(tài)代碼塊實(shí)現(xiàn)單例模式
??private static MySingleton singleon = null;
??private MySingleton() {}
??static {
????singleon = new MySingleton();
??}
??public static MySingleton getInstance() {
????return singleon;
??}
}
結(jié)果
1209285429
1209285429
1209285429
結(jié)論:靜態(tài)代碼塊只在類加載時(shí)執(zhí)行题诵,因而只有一個(gè)實(shí)體對(duì)象,從結(jié)果來(lái)看层皱,線程也是安全的
5.使用枚舉數(shù)據(jù)類型實(shí)現(xiàn)單例模式
實(shí)現(xiàn)代碼
public class ClassFactory {
??private enum MyEnumSingleton {
????singletonFactory;
????private MySingleton instance;
????private MyEnumSingleton() {// 枚舉類的構(gòu)造方法在類加載是被實(shí)例化
??????instance = new MySingleton();
????}
????public MySingleton getInstance() {
??????return instance;
????}
??}
??public static MySingleton getInstance() {
????return MyEnumSingleton.singletonFactory.getInstance();
??}
}
結(jié)果
1139700714
1139700714
1139700714
結(jié)論:枚舉實(shí)現(xiàn)單例模式是線程安全的