Java併發程式設計之安全發布物件的四種方法

2021-09-11 17:34:30 字數 2781 閱讀 4433

(1).在靜態初始化函式中初始化乙個物件的引用

(2).講物件的引用儲存到volatile型別域或者atomicreference物件中

(3).講物件的引用儲存到某個正確構造物件的final型別域

(4).講物件的引用儲存到乙個由鎖保護的域中

(1)懶漢式單例模式

/**

* 懶漢式單例

* 在需要用到物件的時候才去建立物件,在多執行緒下是執行緒不安全的寫法

*/public class publishexample1

public static publishexample1 getinstance()

return publishexample1;

}}

最簡單的懶漢式單例,多執行緒下是執行緒不安全的。

(2)餓漢式單例模式

/**

* 餓漢式單例

* 在類裝載的時候建立物件,在多執行緒下是執行緒安全的

*/public class publishexample2

}

或者還可以使用靜態**塊來建立物件

public class publishexample6 

public static publishexample6 getinstance()

}

在多執行緒下是執行緒安全的,但是缺點也很明顯,就是當需要在類的建構函式中初始化過多資源的時候會造成速度上效能的減慢,而且必須要在程式中被引用到該物件才能不造成資源的浪費,因為該類例項物件的初始化是在類裝載的時候就建立完成的。 

(3)懶漢式單例(使用靜態方法synchronized關鍵字)

/**

* 懶漢式單例

* 在建立物件的靜態工廠方法中加入了鎖,在多執行緒下是執行緒安全的

* 不推薦在多執行緒下使用這種單例模式建立物件

*/public class publishexample3

public synchronized static publishexample3 getinstance()

return publishexample3;

}}

(4)懶漢式單例(雙重同步鎖單例模式)

/**

* 懶漢式單例(雙重同步鎖單例模式)

* 在需要用到物件的時候才去建立物件,在多執行緒下是執行緒不安全的寫法

*/public class publishexample4

public static publishexample4 getinstance()}}

return publishexample4;

}}

首先,這裡還是使用了synchronized關鍵字來進行加鎖,不過不同的是鎖不是加在了整個靜態方法上了,這樣可以減少synchronized對效能產生的開銷,因為當乙個執行緒執行到建立物件這一行**的時候,這時物件已經建立完成了,假如這個時候又有乙個執行緒訪問到這個方法,它可以不用等待上乙個執行緒執行完就直接判斷當前物件是否為空,這樣大大地減少了synchronized關鍵字帶來的效能上的開銷,但是遺憾的是,在多執行緒下,這仍舊是執行緒不安全的。

理由:由於jvm和cpu的優化,會導致指令重排序的出現。重排序意思是jvm會讓你的**執行順序發生改變,但這些改變並不會影響你**順序下的結果。

當我們建立物件時,主要可以分成3步:

1.分配物件的記憶體空間

2.初始化物件

3.設定instance指向剛分配的記憶體

但是當我們的jvm優化發生指令重排序之後可以變成

1.分配物件的記憶體空間

3.設定instance指向剛分配的記憶體

2.初始化物件

假如現在又兩個執行緒a和b,a執行到了publishexample4 = new pulishexample4()這句**,這句**就是包含了第2步和第3步的操作,而b此時執行到了第一層判空的**,如果發生了重排序,a先執行了第3步,此時第2步的初始化物件還沒執行,就是說publishexample4這個引用指向的物件是空,而此時b剛好執行到判空條件引用就是等於空,直接返回該引用,最後得到的物件就是null。

那麼我們怎樣才能用雙重同步鎖單例來達到執行緒安全的使用尼?我們已經知道造成雙重同步鎖單例的執行緒不安全的原因是指令的重排序問題,那麼怎樣才能使禁止重排序尼?答案就是使用volatile關鍵字修飾引用變數。

private volatile static publishexample5 publishexample5 = null;
使用volatitle關鍵字之後就能使得對於這個變數是不允許重排序的,此時就是執行緒安全的了。

(5)列舉單例模式

/**

* 列舉單例模式

* 在多執行緒模式下是執行緒安全的,並且推薦使用

*/public class publishexample7

public static publishexample7 getinstance()

private enum publishenum

public publishexample7 getinstance()

}}

併發程式設計(七) 安全發布物件

發布物件是指使乙個物件能夠被當前範圍之外的 所使用 物件逸出是一種錯誤的發布,指當乙個物件還沒有構造完成時,就使它被其他執行緒所見 slf4j public class escape private class innerclass escape.this thiscanbeescape publi...

(二)Java併發學習筆記 安全發布物件

上邊關於逸出的概念講述的很是模糊,下面列舉幾個逸出的示例。通過靜態變數引用逸出 public static setknownsecrets public void initialize 上邊 示例中,呼叫initialize方法,發布了knowsecrets物件。當你向knowsecrets中新增乙...

java併發程式設計之Exchanger

exchanger v 可以交換的物件型別 可以在對中對元素進行配對和交換的執行緒的同步點。每個執行緒將條目上的某個方法呈現給 exchange 方法,與夥伴執行緒進行匹配,並且在返回時接收其夥伴的物件。exchanger 可能被視為 synchronousqueue 的雙向形式。exchanger...