新聞中心
- 本章難度:
- 本章重點(diǎn):介紹創(chuàng)建Java單例對(duì)象的七種方式,重點(diǎn)掌握哪些創(chuàng)建方式是線程安全的,哪些方式是線程不安全的,并能夠在實(shí)際項(xiàng)目中靈活運(yùn)用設(shè)計(jì)模式,編寫可維護(hù)的代碼。
大家好,我是冰河~~

創(chuàng)新互聯(lián)公司-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設(shè)、高性價(jià)比愛民網(wǎng)站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫,直接使用。一站式愛民網(wǎng)站制作公司更省心,省錢,快速模板網(wǎng)站建設(shè)找我們,業(yè)務(wù)覆蓋愛民地區(qū)。費(fèi)用合理售后完善,10年實(shí)體公司更值得信賴。
今天給大家介紹《Java極簡(jiǎn)設(shè)計(jì)模式》的第01章,單例設(shè)計(jì)模式(Singleton),多一句沒有,少一句不行,用最簡(jiǎn)短的篇幅講述設(shè)計(jì)模式最核心的知識(shí),好了,開始今天的內(nèi)容。
單例設(shè)計(jì)模式
看幾個(gè)單例對(duì)象的示例代碼,其中有些代碼是線程安全的,有些則不是線程安全的,需要大家細(xì)細(xì)品味,這些代碼也是冰河本人在高并發(fā)環(huán)境下測(cè)試驗(yàn)證過的。
- 代碼一:SingletonExample1
這個(gè)類是懶漢模式,并且是線程不安全的
package io.binghe.concurrency.example.singleton;
/**
* @author binghe
* @version 1.0.0
* @description 懶漢模式,單例實(shí)例在第一次使用的時(shí)候進(jìn)行創(chuàng)建,這個(gè)類是線程不安全的
*/
public class SingletonExample1 {
private SingletonExample1(){}
private static SingletonExample1 instance = null;
public static SingletonExample1 getInstance(){
//多個(gè)線程同時(shí)調(diào)用,可能會(huì)創(chuàng)建多個(gè)對(duì)象
if (instance == null){
instance = new SingletonExample1();
}
return instance;
}
}- 代碼二:SingletonExample2
餓漢模式,單例實(shí)例在類裝載的時(shí)候進(jìn)行創(chuàng)建,是線程安全的
package io.binghe.concurrency.example.singleton;
/**
* @author binghe
* @version 1.0.0
* @description 餓漢模式,單例實(shí)例在類裝載的時(shí)候進(jìn)行創(chuàng)建,是線程安全的
*/
public class SingletonExample2 {
private SingletonExample2(){}
private static SingletonExample2 instance = new SingletonExample2();
public static SingletonExample2 getInstance(){
return instance;
}
}- 代碼三:SingletonExample3
懶漢模式,單例實(shí)例在第一次使用的時(shí)候進(jìn)行創(chuàng)建,這個(gè)類是線程安全的,但是這個(gè)寫法不推薦
package io.binghe.concurrency.example.singleton;
/**
* @author binghe
* @version 1.0.0
* @description 懶漢模式,單例實(shí)例在第一次使用的時(shí)候進(jìn)行創(chuàng)建,這個(gè)類是線程安全的,但是這個(gè)寫法不推薦
*/
public class SingletonExample3 {
private SingletonExample3(){}
private static SingletonExample3 instance = null;
public static synchronized SingletonExample3 getInstance(){
if (instance == null){
instance = new SingletonExample3();
}
return instance;
}
}- 代碼四:SingletonExample4
懶漢模式(雙重鎖同步鎖單例模式),單例實(shí)例在第一次使用的時(shí)候進(jìn)行創(chuàng)建,但是,這個(gè)類不是線程安全的?。。。。?/p>
package io.binghe.concurrency.example.singleton;
/**
* @author binghe
* @version 1.0.0
* @description 懶漢模式(雙重鎖同步鎖單例模式)
* 單例實(shí)例在第一次使用的時(shí)候進(jìn)行創(chuàng)建,這個(gè)類不是線程安全的
*/
public class SingletonExample4 {
private SingletonExample4(){}
private static SingletonExample4 instance = null;
//線程不安全
//當(dāng)執(zhí)行instance = new SingletonExample4();這行代碼時(shí),CPU會(huì)執(zhí)行如下指令:
//1.memory = allocate() 分配對(duì)象的內(nèi)存空間
//2.ctorInstance() 初始化對(duì)象
//3.instance = memory 設(shè)置instance指向剛分配的內(nèi)存
//單純執(zhí)行以上三步?jīng)]啥問題,但是在多線程情況下,可能會(huì)發(fā)生指令重排序。
// 指令重排序?qū)尉€程沒有影響,單線程下CPU可以按照順序執(zhí)行以上三個(gè)步驟,但是在多線程下,如果發(fā)生了指令重排序,則會(huì)打亂上面的三個(gè)步驟。
//如果發(fā)生了JVM和CPU優(yōu)化,發(fā)生重排序時(shí),可能會(huì)按照下面的順序執(zhí)行:
//1.memory = allocate() 分配對(duì)象的內(nèi)存空間
//3.instance = memory 設(shè)置instance指向剛分配的內(nèi)存
//2.ctorInstance() 初始化對(duì)象
//假設(shè)目前有兩個(gè)線程A和B同時(shí)執(zhí)行g(shù)etInstance()方法,A線程執(zhí)行到instance = new SingletonExample4(); B線程剛執(zhí)行到第一個(gè) if (instance == null){處,
//如果按照1.3.2的順序,假設(shè)線程A執(zhí)行到3.instance = memory 設(shè)置instance指向剛分配的內(nèi)存,此時(shí),線程B判斷instance已經(jīng)有值,就會(huì)直接return instance;
//而實(shí)際上,線程A還未執(zhí)行2.ctorInstance() 初始化對(duì)象,也就是說線程B拿到的instance對(duì)象還未進(jìn)行初始化,這個(gè)未初始化的instance對(duì)象一旦被線程B使用,就會(huì)出現(xiàn)問題。
public static SingletonExample4 getInstance(){
if (instance == null){
synchronized (SingletonExample4.class){
if(instance == null){
instance = new SingletonExample4();
}
}
}
return instance;
}
}線程不安全分析如下:
當(dāng)執(zhí)行instance = new SingletonExample4();這行代碼時(shí),CPU會(huì)執(zhí)行如下指令:
1.memory = allocate() 分配對(duì)象的內(nèi)存空間 2.ctorInstance() 初始化對(duì)象 3.instance = memory 設(shè)置instance指向剛分配的內(nèi)存
單純執(zhí)行以上三步?jīng)]啥問題,但是在多線程情況下,可能會(huì)發(fā)生指令重排序。
指令重排序?qū)尉€程沒有影響,單線程下CPU可以按照順序執(zhí)行以上三個(gè)步驟,但是在多線程下,如果發(fā)生了指令重排序,則會(huì)打亂上面的三個(gè)步驟。
如果發(fā)生了JVM和CPU優(yōu)化,發(fā)生重排序時(shí),可能會(huì)按照下面的順序執(zhí)行:
1.memory = allocate() 分配對(duì)象的內(nèi)存空間 3.instance = memory 設(shè)置instance指向剛分配的內(nèi)存 2.ctorInstance() 初始化對(duì)象
假設(shè)目前有兩個(gè)線程A和B同時(shí)執(zhí)行g(shù)etInstance()方法,A線程執(zhí)行到instance = new SingletonExample4(); B線程剛執(zhí)行到第一個(gè) if (instance == null){處,如果按照1.3.2的順序,假設(shè)線程A執(zhí)行到3.instance = memory 設(shè)置instance指向剛分配的內(nèi)存,此時(shí),線程B判斷instance已經(jīng)有值,就會(huì)直接return instance;而實(shí)際上,線程A還未執(zhí)行2.ctorInstance() 初始化對(duì)象,也就是說線程B拿到的instance對(duì)象還未進(jìn)行初始化,這個(gè)未初始化的instance對(duì)象一旦被線程B使用,就會(huì)出現(xiàn)問題。
- 代碼五:SingletonExample5
懶漢模式(雙重鎖同步鎖單例模式)單例實(shí)例在第一次使用的時(shí)候進(jìn)行創(chuàng)建,這個(gè)類是線程安全的,使用的是 volatile + 雙重檢測(cè)機(jī)制來禁止指令重排達(dá)到線程安全
package io.binghe.concurrency.example.singleton;
/**
* @author binghe
* @version 1.0.0
* @description 懶漢模式(雙重鎖同步鎖單例模式)
* 單例實(shí)例在第一次使用的時(shí)候進(jìn)行創(chuàng)建,這個(gè)類是線程安全的
*/
public class SingletonExample5 {
private SingletonExample5(){}
//單例對(duì)象 volatile + 雙重檢測(cè)機(jī)制來禁止指令重排
private volatile static SingletonExample5 instance = null;
public static SingletonExample5 getInstance(){
if (instance == null){
synchronized (SingletonExample5.class){
if(instance == null){
instance = new SingletonExample5();
}
}
}
return instance;
}
}- 代碼六:SingletonExample6
餓漢模式,單例實(shí)例在類裝載的時(shí)候(使用靜態(tài)代碼塊)進(jìn)行創(chuàng)建,是線程安全的
package io.binghe.concurrency.example.singleton;
/**
* @author binghe
* @version 1.0.0
* @description 餓漢模式,單例實(shí)例在類裝載的時(shí)候進(jìn)行創(chuàng)建,是線程安全的
*/
public class SingletonExample6 {
private SingletonExample6(){}
private static SingletonExample6 instance = null;
static {
instance = new SingletonExample6();
}
public static SingletonExample6 getInstance(){
return instance;
}
}- 代碼七:SingletonExample7
枚舉方式進(jìn)行實(shí)例化,是線程安全的,此種方式也是線程最安全的
package io.binghe.concurrency.example.singleton;
/**
* @author binghe
* @version 1.0.0
* @description 枚舉方式進(jìn)行實(shí)例化,是線程安全的,此種方式也是線程最安全的
*/
public class SingletonExample7 {
private SingletonExample7(){}
public static SingletonExample7 getInstance(){
return Singleton.INSTANCE.getInstance();
}
private enum Singleton{
INSTANCE;
private SingletonExample7 singleton;
//JVM保證這個(gè)方法絕對(duì)只調(diào)用一次
Singleton(){
singleton = new SingletonExample7();
}
public SingletonExample7 getInstance(){
return singleton;
}
}
} 本文名稱:我們一起聊聊Java極簡(jiǎn)設(shè)計(jì)模式:?jiǎn)卫J剑⊿ingleton)
網(wǎng)頁路徑:http://www.dlmjj.cn/article/dppdcgg.html


咨詢
建站咨詢
