1. 程式人生 > >實戰Java高併發程式設計之Java記憶體模型和執行緒安全

實戰Java高併發程式設計之Java記憶體模型和執行緒安全

Java記憶體模型

原子性:

是指一個操作是不可中斷的.即使多個執行緒一起執行的時候,一個操作一旦開始,就不會被其他執行緒干擾.

一般CPU的指令是原子的.

Q:i++是原子操作嗎?

A:不是.

32位系統來說long型資料的讀寫不是原子性的(因為long有64位),也就是說兩個執行緒同時對long進行寫入的話,對執行緒之間的結果是有干擾的. 有序性: 在併發時,程式的執行可能會出現亂序,直觀感受是寫在前面的後被執行 指令重排可以保證序列語義一致,但是沒有義務保證多執行緒間的語義也一致 一條指令(彙編指令)的執行是可以分為很多步驟的: ---- 取指IF ----譯碼和取暫存器運算元ID ----執行或者有效地址計算EX ----儲存器訪問MEM ----寫回WB 可見性:
可見性是指一個執行緒修改了某一個共享變數的值,其他執行緒是否能夠立即知道這個修改. 顯然,對於序列程式來說,可見性問題是不存在的.因為你在任何一個操作步驟中修改了某個變數,那麼在後續的步驟中,讀取這個變數的值,一定是修改後的新值 並行中,其他程式未必可以馬上知道這個改動. ----編譯器優化和硬體優化(如寫吸收,批操作)會造成這個影響 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());
	}
}
執行以後會發現不加valitile結果不相同.這就是可見性所致.具體原因,涉及到java虛擬機器,目前還不懂.
Happen-Before規則(先行發生)
  • 程式順序原則:一個執行緒內保證語義的序列性.a = 1;b = a+1;類似指令不會重排
  • volatile規則:volatile變數的寫,先發生於讀,這保證了volatile變數的可見性
  • 鎖規則:解鎖(unlock)必然發生在隨後的加鎖(lock)前
  • 傳遞性:A先於B,B先於C,那麼A必然先於C
  • 執行緒的start()方法先於它的每一個動作
  • 執行緒的所有操作先於執行緒的終結(Thread.join())
  • 執行緒的中斷(interrupt())先於被中斷執行緒的程式碼
  • 物件的建構函式執行結束先於finalize()方法
執行緒安全的概念 指某個函式、函式庫在多執行緒環境中被呼叫時,能夠正確地處理各個執行緒的區域性變數,使程式功能正確完成。 i++在多執行緒下訪問的情況:
最簡單的修改就是在++操作時候使用synchronized關鍵字