1. 程式人生 > >Java併發之基礎知識

Java併發之基礎知識

同一程序的所有執行緒

  • 彼此獨立執行
  • 共享程序的記憶體地址空間
  • 訪問相同的變數並在同一堆上分配物件

執行緒安全性

單語句不一定有原子性,可能包含多個操作 例value++ 1. 讀取value 2. value+1 3. 寫入value

執行緒安全守則

  • 不線上程之間共享狀態變數
  • 將狀態變數修改為不可變的變數
  • 在訪問狀態變數時進行同步

servlet執行緒安全性

它既不包含任何域,也不包含任何對其他類中域的引用 臨時狀態僅存在於執行緒棧上的區域性變數中,只能由當前執行緒訪問

無狀態物件一定是執行緒安全的

競態條件

非執行緒安全域+非執行緒安全操作 => 多執行緒的交替執行時序 => 影響正確性

先檢查後執行 => “延遲初始化” => A,B都通過了檢查,然後AB都進行初始化 => 衝突

加鎖機制

內建鎖

靜態的synchronize方法以class物件作為鎖

重入

“重入”意味著獲取鎖的操作的粒度是執行緒,而不是“呼叫”。 子類可以進入父類的synchronize塊

物件共享

可見性

執行緒變數 <——-> 主執行緒變數 並非即時發生

重排序

沒有同步時,編譯器,處理器以及執行時,都可能對操作的執行順序進行調整

volatile變數:輕量級弱同步

將變數的更新通知到其他執行緒,不會重排序,不會被快取

執行緒封閉:只在單執行緒內訪問資料

servlet 單執行緒同步方式

Servlet類本質上也是一個普通的類,並且Servlet容器預設只允許單個例項存在。當請求達到伺服器的時候,Servlet例項如果已經存在的話則直接載入該例項,如果該Servlet類還未例項化則會先初始化這個Servlet。當請求到達Web伺服器時,Web伺服器中有一個執行緒池,它會從執行緒池中取一個工作執行緒,通過該執行緒呼叫請求的Servlet。因此,對Servlet來說,可以同時被好幾個請求呼叫。請求結束後,執行緒放回執行緒池。

這種設計帶來的好處是,Servlet單例項,減少了生成Servlet的開銷。通過執行緒池響應請求,避免了不斷建立執行緒和銷燬執行緒的開銷,提高了效能。但是這種多執行緒操縱單例項的模式,也會有一些副作用,那就是可能造成資料的不一致。

ThreadLocal類:當前執行緒儲存的資訊 當執行緒終止後,這些值會作為垃圾回收

ThreadLocal 提供了執行緒本地的例項。它與普通變數的區別在於,每個使用該變數的執行緒都會初始化一個完全獨立的例項副本。ThreadLocal 變數通常被private static修飾。當一個執行緒結束時,它所使用的所有 ThreadLocal 相對的例項副本都可被回收。

不變性

  • 不可變物件一定執行緒安全
  • final域能確定初始化過程的安全性,在共享時無須同步
Final 變數在併發當中,原理是通過禁止cpu的指令集重排序(重排序詳解http://ifeve.com/java-memory-model-1/ http://ifeve.com/java-memory-model-2/),來提供現成的課件性,來保證物件的安全釋出,防止物件引用被其他執行緒在物件被完全構造完成前拿到並使用。

與前面介紹的鎖和volatile相比較,對final域的讀和寫更像是普通的變數訪問。對於final域,編譯器和處理器要遵守兩個重排序規則:

在建構函式內對一個final域的寫入,與隨後把這個被構造物件的引用賦值給一個引用變數,這兩個操作之間不能重排序。
初次讀一個包含final域的物件的引用,與隨後初次讀這個final域,這兩個操作之間不能重排序。

與Volatile 有相似作用,不過Final主要用於不可變變數(基本資料型別和非基本資料型別),進行安全的釋出(初始化)。而Volatile可以用於安全的釋出不可變變數,也可以提供可變變數的可見性。