首先咱們在作併發編程的的時候會考慮到原子性丶可見性和有序性,在宏觀上會考慮到安全性丶活躍性和性能;git
線程工做內存: 是指 Cpu 的 '寄存器' 和 '高速緩存',線程的 工做內存/本地內存 是指cpu的寄存器和高速緩存的抽象描述,數據讀取順序優先級 是:寄存器->高速緩存->內存github
例如:線程A在主存中年將變量age=0拉去到本身的工做內存中,而後作了age = 5,固然這個操做是在cpu的寄存器中進行的,而後寫會高速緩存中,這時線程A的高速緩存還未執行同步主內存的操做,線程B又將age=0從主存拉取到了線程B的工做內存中,致使A線程已經更新可是B線程看不到的可見性問題;編程
例如:當線程A從主內存中將共享變量Count加載到線程A的工做內存後,發生了線程切換,這個時候線程B也將共享變量Count從主內存加載到了線程B的工做內存,這時線程A和B的工做內存中count都是0,線程B執行了Count = Count + 1,而後寫回到主內存,這時候線程切換完成,回到了線程A再次執行 Count = Count + 1,再將線程A工做內存計算過的count寫回主內存,如今咱們獲得的主內存呢中Count值是1而不是2。緩存
在這裏講一個例子,就是獲取單例雙重檢查鎖(double-checked locking)判斷:安全
/**
* @Auther: lantao
* @Date: 2019-03-28 14:32
* @Company: 隨行付支付有限公司
* @maill: lan_tao@suixingpay.com
* @Description: TODO
*/
public class Test1 {
private DoMain doMain;
public DoMain getDoMain(){
if(doMain == null){
synchronized (this.getClass()){
if(doMain == null){
doMain = new DoMain("");
}
return doMain;
}
}else{
return doMain;
}
}
}
複製代碼
在上邊的代碼中在synchronized內和外都有一個if判斷,判斷doMain是否爲null操做,有不少人對synchronized中的if null判斷不理解,其實能夠這樣想,線程A和線程B都執行到了synchronized這裏進行競爭鎖,結果A獲得鎖,判斷if null,結果還未實例化,繼續進行實例化,而後return對象並釋放鎖,這時線程B獲取到了鎖進入if null判斷,發現doMain已經被線程A實例化過了,直接返回實例便可,第二個if null的做用就在這裏;bash
看上去上邊的代碼是完美的,可是new的操做上咱們理解是:多線程
可是實際上優化後(指令重排)的執行路徑多是這樣的:併發
博客地址:lantaoblog.site性能