目錄
我們一直強(qiáng)調(diào)成都網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì)對(duì)于企業(yè)的重要性,如果您也覺得重要,那么就需要我們慎重對(duì)待,選擇一個(gè)安全靠譜的網(wǎng)站建設(shè)公司,企業(yè)網(wǎng)站我們建議是要么不做,要么就做好,讓網(wǎng)站能真正成為企業(yè)發(fā)展過程中的有力推手。專業(yè)網(wǎng)站制作公司不一定是大公司,創(chuàng)新互聯(lián)作為專業(yè)的網(wǎng)絡(luò)公司選擇我們就是放心。前言:
單線程下的單例模式
餓漢模式
懶漢模式
多線程下的單例模式
懶漢模式的修改
1.加鎖
2.有條件的加鎖
3.解決內(nèi)存可見性和指令重排序
本片文章介紹設(shè)計(jì)模式中的一個(gè)模式——單例模式。
單例模式就是只允許創(chuàng)建出一個(gè)實(shí)例的類。比如之前在使用JDBC編程的時(shí)候的DataSource這個(gè)類,就可以使用單例模式。見這篇文章http://t.csdn.cn/uq1lR。
其中單例模式有很多種實(shí)現(xiàn)方法,這里只用懶漢模式和餓漢模式來實(shí)現(xiàn)單例模式。
單線程中,沒有線程安全問題,其代碼會(huì)簡單很多。
餓漢模式餓漢模式體現(xiàn)出一個(gè)字——急。因?yàn)檫@個(gè)實(shí)例直接就是在類加載階段就被創(chuàng)建出來。
class SingletonHungry{
// 用static修飾,這樣在類加載階段就有了這個(gè)實(shí)例
private static SingletonHungry instance = new SingletonHungry();
// 用靜態(tài)公開方法返回實(shí)例
public static SingletonHungry getInstance() {
return instance;
}
// 為了防止實(shí)例化多個(gè)對(duì)象,把構(gòu)造方法用private修飾
private SingletonHungry(){};
}
public class SingletonTest1 {
public static void main(String[] args) {
SingletonHungry instance1 = SingletonHungry.getInstance();
SingletonHungry instance2 = SingletonHungry.getInstance();
System.out.println(instance1 == instance2);
//SingletonHungry instance3 = new SingletonHungry();
}
}
懶漢模式突出一個(gè)字——懶。這個(gè)實(shí)例是只有調(diào)用獲取實(shí)例方法的時(shí)候才創(chuàng)建出來。
class SingletonLazy{
private static SingletonLazy instance = null;
// 只有在調(diào)用了該方法后才創(chuàng)造出了實(shí)例
public static SingletonLazy getInstance() {
// 如果已經(jīng)創(chuàng)建了該實(shí)例,就直接返回之前的實(shí)例
if (instance == null) {
instance = new SingletonLazy();
}
return instance;
}
// 為了防止實(shí)例化多個(gè)對(duì)象,把構(gòu)造方法用private修飾
private SingletonLazy(){}
}
public class SingletonTest2 {
public static void main(String[] args) {
SingletonLazy instance1 = SingletonLazy.getInstance();
SingletonLazy instance2 = SingletonLazy.getInstance();
System.out.println(instance1 == instance2);
//SingletonLazy instance3 = new SingletonLazy();
}
}
代碼結(jié)果如上。?
在上述代碼中,如果考慮多線程的話
餓漢模式?jīng)]有線程安全問題,它直接就是在類加載是創(chuàng)建出了一個(gè)實(shí)例,使用該實(shí)例也沒有其他修改的操作,直接返回即可。
懶漢模式是有線程安全問題。它又要判斷比較實(shí)例是否為null,又要?jiǎng)?chuàng)建一個(gè)實(shí)例,最后才返回實(shí)例。其中對(duì)于實(shí)例是由修改的操作的。只要有修改操作,就可能會(huì)有線程安全問題。如下圖:
懶漢模式的修改 1.加鎖對(duì)于這種又有讀,又有寫的操作,保持原子性——加鎖即可。
public SingletonThread getInstance() {
// 這里對(duì)于load cmp new這幾步加鎖,保持了其原子性
synchronized (SingletonThread.class) {
if (instance == null) {
instance = new SingletonThread();
}
}
return instance;
}
2.有條件的加鎖但是加鎖是一種開銷比較大的操作,上述加鎖操作并不是每次都要加鎖的。如果已經(jīng)創(chuàng)建了實(shí)例,直接返回實(shí)例即可。
public SingletonThread getInstance() {
// 如果實(shí)例未被創(chuàng)建,用加鎖的方法創(chuàng)建實(shí)例
// 如果創(chuàng)建,直接返回
if (instance == null) {
// 這里對(duì)于load cmp new這幾步加鎖,保持了其原子性
synchronized (SingletonThread.class) {
if (instance == null) {
instance = new SingletonThread();
}
}
}
return instance;
}
3.解決內(nèi)存可見性和指令重排序內(nèi)存可見性:因?yàn)閕nstance要讀取并修改,所以對(duì)于內(nèi)存可見性的問題也要預(yù)防。
指令重排序:
上面的new實(shí)例的指令又分為三個(gè)順序步驟:
①申請(qǐng)內(nèi)存空間
②調(diào)用構(gòu)造方法,實(shí)例化一個(gè)對(duì)象
③把內(nèi)存空間的地址賦值給這個(gè)對(duì)象
這幾步可能可能會(huì)變成①③②。單線程下沒有問題,但是多線程就會(huì)有問題了。
要想解決這兩個(gè)問題,使用volatile關(guān)鍵字修飾instance即可。
private volatile static SingletonThread instance = null;
完整的懶漢模式的線程安全代碼如下:
// 修改懶漢模式,使其線程安全
class SingletonThread {
// 使用volatile解決內(nèi)存可見性和指令重排序問題
private volatile static SingletonThread instance = null;
public SingletonThread getInstance() {
// 如果實(shí)例未被創(chuàng)建,用加鎖的方法創(chuàng)建實(shí)例
// 如果創(chuàng)建,直接返回
if (instance == null) {
// 這里對(duì)于load cmp new這幾步加鎖,保持了其原子性
synchronized (SingletonThread.class) {
if (instance == null) {
instance = new SingletonThread();
}
}
}
return instance;
}
}
有什么問題評(píng)論區(qū)指出。希望可以幫到你。
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購,新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧