平時我們建立的物件往往不會考慮到安全物件的概念,這可能比較陌生,但是你面試的時候面試官很喜歡問你執行緒安全的單例模式,而這就是相關的知識點~
發布:使物件能夠在除了當前作用域之外的地方使用~
最常用的方法:將物件的引用儲存到乙個公有的靜態變數中,讓任何類和執行緒都能看到該物件。
逸出:某個物件不應該被發布而發布了~
一般通過類的非私有方法返回物件引用或者通過公有靜態變數來發布物件,不安全物件發布會導致其他執行緒可以修改~
public class unsafepublish ;
//通過這個方法能得到私有域的引用,其他執行緒可能會修改。
public string getstates()
public static void main(string args) ", arrays.tostring(unsafepublish.getstates()));
unsafepublish.getstates()[0] = "d";
log.info("{}", arrays.tostring(unsafepublish.getstates()));
}}
可以看得到,陣列states已經逸出它的作用域,通過這個方法能得到私有域的引用,其他執行緒可能會修改。
有一句話注意:不要在構造過程中使this引用逸出
建構函式過程中啟動乙個執行緒,無論是隱式還是顯示啟動,都會造成this引用逸出,新執行緒總是會在所屬新執行緒總會在所屬物件構造完畢之前就已經看到他了,所以如果要在建構函式中建立執行緒,不要啟動,而是要採用專有的start或初始化方法統一啟動執行緒,
解決辦法:一般採用工廠方法和私有建構函式來建立。目的是物件未完成構造之前不可以將其發布。
正如**所示,thisescape建構函式中引入乙個內部類,而內部類會自動持有其外部類的this引用,source.registerlistener會將內部類發布出去,從而thisescape.this引用也隨著內部類被發布了出去。但此時thisescape物件還沒有構造完成 —— id已被賦值為1,但name還沒被賦值,仍然為null。
知識聯絡:內部類,匿名內部類都可以訪問外部類物件的域,因為內部類構造的時候,會把外部類的物件this隱式的作為乙個引數傳遞給內部類的構造方法,這個工作時編譯器完成的~
public class thisescape
});
name = "flysqrlboy";
} }
單例模式詳情
在類載入時就進行建立~
public class singleton
// 單例物件
private static singleton instance = new singletonexample2();
// 靜態的工廠方法
public static singleton getinstance()
}
缺點:
適用:一般的,私有構造(外部不能new物件),單例物件,靜態工廠方法~
安全發布最常見的就是不可變物件和執行緒封閉。
3.1 不可變物件滿足的條件:
一般的,將類宣告final,所有成員設定為私有,對變數不提供setter方法,深度拷貝
3.2 final關鍵字:
當然,除了設計成不可變物件,還有就是執行緒封閉,把物件封裝到乙個執行緒裡,只有這乙個執行緒能看到這個的物件,儘管這個物件不是安全的,也沒有關係。
3.3 執行緒封閉:
非執行緒安全物件
今天的微博有人討論到物件池,我想到之前專案的實現,應該用模板來實現啊,唉,還是被前人的想法給框定了,只是實現乙個特別簡單,花了幾分鐘寫了個 const int defaultpoolsize 1024 template class cssobejctpool cssobejctpool int32 ...
(二)Java併發學習筆記 安全發布物件
上邊關於逸出的概念講述的很是模糊,下面列舉幾個逸出的示例。通過靜態變數引用逸出 public static setknownsecrets public void initialize 上邊 示例中,呼叫initialize方法,發布了knowsecrets物件。當你向knowsecrets中新增乙...
併發程式設計(七) 安全發布物件
發布物件是指使乙個物件能夠被當前範圍之外的 所使用 物件逸出是一種錯誤的發布,指當乙個物件還沒有構造完成時,就使它被其他執行緒所見 slf4j public class escape private class innerclass escape.this thiscanbeescape publi...