0 概述
所謂同步,就是給多個線程規定一個執行的順序(或稱為時序),要求某個線程先執行完一段代碼后,另一個線程才能開始執行。
第一種情況:多個線程訪問同一個變量:
1.一個線程寫,其它線程讀:這種情況不存在同步問題,因為只有一個線程在改變內存中的變量,內存中的變量在任意時刻都有一個確定的值;
2.一個線程讀,其它線程寫:這種情況會存在同步問題,主要是多個線程在同時寫入一個變量的時候,可能會發生一些難以察覺的錯誤,導致某些線程實際上并沒有真正的寫入變量;
3.幾個線程寫,其它線程讀:情況同2。
多個線程同時向一個變量賦值,就會出現問題,這是為什么呢?
我們編程采用的是高級語言,這種語言是不能被計算機直接執行的,一條高級語言代碼往往要編譯為若干條機器代碼,而一條機器代碼,CPU也不一定是在一個CPU周期內就能完成的。計算機代碼必須要按照一個“時序”,逐條執行。
舉個例子,在內存中有一個整型變量number(4字節),那么計算++number(運算后賦值)就至少要分為如下幾個步驟:
1. 尋址:由CPU的控制器找尋到number變量所在的地址;
2. 讀?。簩umber變量所在的值從內存中讀取到CPU寄存器中;
3. 運算:由CPU的算術邏輯運算器(ALU)對number值進行計算,將結果存儲在寄存器中;
4. 保存:由CPU的控制器將寄存器中保存的結果重新存入number在內存中的地址。
這是最簡單的時序,如果牽扯到CPU的高速緩存(CACHE),則情況就更為復雜了。
圖1 CPU結構簡圖
在多線程環境下,當幾個線程同時對number進行賦值操作時(假設number初始值為0),就有可能發生沖突:
當某個線程對number進行++操作并執行到步驟2(讀取)時(0保存在CPU寄存器中),發生線程切換,該線程的所有寄存器狀態被保存到內存后后,由另一個線程對number進行賦值操作。當另一個線程對number賦值完畢(假設將number賦值為10),切換回第一個線程,進行現場恢復,則在寄存器中保存的number值依然為0,該線程從步驟3繼續執行指令,最終將1寫入到number所在內存地址,number值最終為1,另一個線程對number賦值為10的操作表現為無效操作。
看一個例子:
[csharp]view plaincopy注意,原子操作中,要賦值的變量都是以引用方式傳遞參數的,這樣才能在原子操作方法內部直接改變變量的值,才能完全避免非安全的賦值操作。
下面我們將前一節中出問題的代碼做一些修改,修改其ThreadWork方法,在多線程下能夠安全的操作同一個變量:
[csharp]view%20plaincopy新聞熱點
疑難解答