本系列博客是對《Java併發編程實戰》的一點總結,本篇主要講解如下幾個內容,內容會比較枯燥。可能你們看標題不能能直觀的感覺出到底什麼意思,這就是專業術語,哈哈,解釋下,術語(terminology)是在特定學科領域用來表示概念的稱謂的集合,在我國又稱爲名詞或科技名詞(不一樣於語法學中的名詞)。術語是經過語音或文字來表達或限定科學概念的約定性語言符號,是思想和認識交流的工具。我就用白話文來給你們解釋下這些術語。java
什麼是線程安全?這算是老生常談的問題了,相信你們在面試的過程當中也遇到過,在線程安全的定義中,最核心的概念就是正確性,若是對線程安全性的定義是模糊的,那麼就是缺少對正確性的清晰定義。正確性的含義是,某個類的行爲與其規範徹底一致,在良好的規範中一般會定義各類不變性條件來約束對象的狀態,以及定義各類後驗條件來描述對象操做的結果。說白了就是一個類不管是在單線程環境仍是多線程環境中都能正確的執行,那麼這個類就是線程安全的。若是在線程交替執行的過程當中致使不可預料的結果,那麼就是線程不安全的。面試
假若有一個變量,如今對它進行讀寫操做,可見性說的就是當前線程對變量的寫操做是否對其它線程可見,就是其它線程能不能知道你對這個變量作了修改。若是不能保證可見,必須使用同步機制。不然當其餘線程來讀這個變量的時候,可能會獲得一個已經失效的值。這個值就被稱爲失效數據。
在這裏提醒你們,對於非volatile類型的long和double變量JVM容許將64位的讀操做或寫操做分解爲兩個32位的操做,當讀一個非volatile類型的long變量時,若是讀寫操做是在不一樣的線程中執行,那麼極可能會讀取到某個值的高32位和另外一個值的低32位,因此在多線程環境中使用共享可變的long和double等類型的變量時不安全的,除非使用關鍵字volatile來聲明它們,或者用鎖保護起來。數據庫
加鎖機制既能夠確保可見性又能夠確保原子性,而volatile變量只能確保可見性,千萬不要用它來確保原子性操做。
編程
發佈一個對象的意思就是使對象可以在當前做用域以外的代碼中使用,例如,將一個指向該對象的的引用保存到其餘代碼能夠訪問的地方,或者在某一個非私有的方法中返回該引用,或者將引用傳遞到其餘類方法中。當某個不該該發佈的對象被髮布時,這種狀況被稱爲逸出。安全
當訪問共享的可變數據時,一般須要使用同步。一種避免使用同步的方式就是不一樣享數據,若是僅在單線程內訪問數據,就不須要同步,這種技術被稱爲線程封閉,它是實現線程安全性最簡單的方法之一。下面介紹幾種線程封閉技術。bash
Ad-hoc線程封閉多線程
Ad-hoc線程封閉是指,維護線程封閉性的職責徹底有程序實現來承擔。例如可見性修飾符或局部變量,能將對象封閉到目標線程上。事實上對於線程封閉對象一般保存在共有變量中。Ad-hoc線程封閉是很是脆弱的,因此程序中儘可能少使用它,可使用如下兩種技術(棧封閉,ThreadLocal)。併發
棧封閉ide
棧封閉也被成爲線程內部使用或者線程局部使用,不要與ThredaLocal混淆,比Ad-hoc更易於維護,也更加健壯。在棧封閉中,只能經過局部變量才能訪問對象。函數
//僞代碼
public void test(){
//定義一個變量
Set set ;
// 實例化一個TreeSet對象,並將該對象的一個引用保存到set中。
set = new TreeSet();
}
複製代碼
這樣TreeSet對象就被封閉在局部變量中,所以也被封閉到執行線程中,它位於執行線程的棧中,其餘線程沒法訪問這個棧。
ThreadLocal
維持線程封閉性的一種更爲規範的方法是使用ThreadLocal,這個類能使線程中的某個值與保存值的對像關聯起來,ThreadLocal提供了get與set等訪問接口或方法,這些方法爲每一個使用該變量的線程都存有一份獨立的副本,所以get老是返回由當前線程執行set時設置的最新值。ThreadLocal一般用於防止對可變對像的單實例變量或全局變量進行共享。
//保存一個數據庫鏈接對像
public static ThreadLocal<Connection> connectionThreadLocal =
new ThreadLocal<Connection>(){
@Override
protected Connection initialValue() {
return DriverManager.getConnection(DB_URl);
}
};
//每一個線程使用時直接get
public static Connection getConnection(){
return connectionThreadLocal.get();
}
複製代碼
若是某個對像在被建立以後其狀態就不能被修改,那麼這個對象就是不可變對象,線程安全性是是不可變對象的固有屬性之一。當知足一下條件時,對象纔是不可變的:
Final域: 用於構造不可變對象。final類型的域是不能修改的(但若是final域所引用的對象是可變的,那麼這些引用的對象是能夠修改的)。然而在java內存模型中,final域還有着特殊的語義。final域能確保初始化過程的安全性,從而能夠不受限制的訪問不可變對象,並在共享這些對象時無須同步。
你們看后辛苦點個贊點個關注哦!查看我的主頁,有更多的博客哦。若有錯誤,煩請指正。 有興趣加羣一塊兒交流。
![]()