當多個執行緒訪問了相同的資源(同一記憶體區、系統、檔案)時可能會導致一些問題。
- 實際上,這些問題只有在乙個或多個執行緒對這些資源進行了寫操作時,才有可能發生,只要資源沒有發生變化,多個執行緒讀取相同的資源就是安全的
多個執行緒執行下面**可能會出錯:
public
class counter
}
想象下執行緒a和b同時執行同乙個counter物件的add()方法,我們無法知道作業系統何時會在兩個執行緒之間切換。jvm並不是將這段**視為單條指令來執行的,而是按照下面的順序:
從記憶體獲取 this.count 的值放到暫存器
將暫存器中的值增加value
將暫存器中的值寫回記憶體
觀察執行緒a和b交錯執行會發生什麼:
this.count = 0;
a: 讀取 this.count 到乙個暫存器 (0)
b: 讀取 this.count 到乙個暫存器 (0)
b: 將暫存器的值加2
b: 回寫暫存器值(2)到記憶體. this.count 現在等於 2
a: 將暫存器的值加3
a: 回寫暫存器值(3)到記憶體. this.count 現在等於 3
兩個執行緒分別加了2和3到count變數上,兩個執行緒執行結束後count變數的值應該等於5。然而由於兩個執行緒是交叉執行的,兩個執行緒從記憶體中讀出的初始值都是0。然後各自加了2和3,並分別寫回記憶體。最終的值並不是期望的5,而是最後寫回記憶體的那個執行緒的值,上面例子中最後寫回記憶體的是執行緒a,但實際中也可能是執行緒b。如果沒有採用合適的同步機制,執行緒間的交叉執**況就無法預料。
當兩個執行緒競爭同一資源時,如果對資源的訪問順序敏感,就稱存在競態條件。導致競態條件發生的**區稱作臨界區。上例中add()方法就是乙個臨界區,它會產生競態條件。在臨界區中使用適當的同步就可以避免競態條件。
Java的高併發程式設計系列(三)
鎖定某物件o,如果o的屬性發生改變,不影響鎖的使用,但是如果o變成另外乙個物件,則鎖定的物件發生改變,應該避免將鎖定物件的引用變成另外乙個物件。public class demo17 catch interruptedexception e system.out.println thread.cur...
實戰Java高併發程式設計(三)JDK並發包
同步控制 重入鎖 重入鎖可以完全替代synchronized關鍵字。其使用方法如下 public reentrantlock lock new reentrantlock public void run finally 由於其通過人工進行lock和unlock,因此比synchronized更好控制...
java併發程式設計的三大問題
背景 計算機處理速度 cpu 記憶體 io 為了平衡三者的速度差異 cpu 增加了快取 作業系統增加了程序 執行緒,以分時復用 cpu 編譯程式優化指令執行次序 可見性 乙個執行緒對共享變數的修改,另外乙個執行緒能夠立刻看到 原子性 乙個或者多個操作在 cpu 執行的過程中不被中斷的特性 1 快取導...