實戰Java高併發程式設計之Java記憶體模型和執行緒安全
阿新 • • 發佈:2019-01-28
Java記憶體模型
原子性:
是指一個操作是不可中斷的.即使多個執行緒一起執行的時候,一個操作一旦開始,就不會被其他執行緒干擾.
一般CPU的指令是原子的.
Q:i++是原子操作嗎?
A:不是.
32位系統來說long型資料的讀寫不是原子性的(因為long有64位),也就是說兩個執行緒同時對long進行寫入的話,對執行緒之間的結果是有干擾的. 有序性: 在併發時,程式的執行可能會出現亂序,直觀感受是寫在前面的後被執行 指令重排可以保證序列語義一致,但是沒有義務保證多執行緒間的語義也一致 一條指令(彙編指令)的執行是可以分為很多步驟的: ---- 取指IF ----譯碼和取暫存器運算元ID ----執行或者有效地址計算EX ----儲存器訪問MEM ----寫回WB 可見性:執行以後會發現不加valitile結果不相同.這就是可見性所致.具體原因,涉及到java虛擬機器,目前還不懂.public class VisibilityTest extends Thread { private volatile boolean stop; public void run() { int i = 0; while (!stop) { i++; } System.out.println("finish loop,i=" + i); } public void stopIt() { stop = true; } public boolean getStop() { return stop; } public static void main(String[] args) throws Exception { VisibilityTest v = new VisibilityTest(); v.start(); Thread.sleep(1000); v.stopIt(); Thread.sleep(2000); System.out.println("finish main"); System.out.println(v.getStop()); } }
Happen-Before規則(先行發生)
- 程式順序原則:一個執行緒內保證語義的序列性.a = 1;b = a+1;類似指令不會重排
- volatile規則:volatile變數的寫,先發生於讀,這保證了volatile變數的可見性
- 鎖規則:解鎖(unlock)必然發生在隨後的加鎖(lock)前
- 傳遞性:A先於B,B先於C,那麼A必然先於C
- 執行緒的start()方法先於它的每一個動作
- 執行緒的所有操作先於執行緒的終結(Thread.join())
- 執行緒的中斷(interrupt())先於被中斷執行緒的程式碼
- 物件的建構函式執行結束先於finalize()方法
最簡單的修改就是在++操作時候使用synchronized關鍵字