操作的原子性與執行緒安全
阿新 • • 發佈:2019-07-11
本案例來源於java zone社群,由於原始碼裡面存在一些自己開發的註解,我暫時沒找到相關的文件,所以我做了一些修改。用的都是java SDK的API。 關於概念:
-
原子性:即一個操作或者多個操作 要麼全部執行並且執行的過程不會被任何因素打斷,要麼就都不執行。
-
執行緒安全:就是多執行緒訪問時,採用了加鎖機制,當一個執行緒訪問該類的某個資料時,進行保護,其他執行緒不能進行訪問直到該執行緒讀取完,其他執行緒才可使用。不會出現資料不一致或者資料汙染。
-
執行緒不安全:就是不提供資料訪問保護,有可能出現多個執行緒先後更改資料造成所得到的資料是髒資料
進入正題,如果可以從多個執行緒呼叫所有方法而沒有外部同步,則類是執行緒安全的。為了實現這一點,執行緒安全方法必須是原子的,例如,其他執行緒只能看到方法之前或之後呼叫之間的狀態。以下示例說明了為什麼執行緒安全方法必須是原子的:
public class TR extends FanLibrary { private volatile int i = 0; public void ss() { sleep(100);//為了更容易出現效果 i++; } @Before public void be() { output("before"); } @Test public void sdfa() throws InterruptedException { Thread first = new Thread(() -> { ss(); }); Thread second = new Thread(() -> { ss(); }); first.start(); second.start(); first.join(); second.join(); output(i); } @After public void ds() { output("after"); } }
控制檯輸出,以下內容可能會出現,程式碼中sleep(100)的原因:
INFO-> before
INFO-> 1
INFO-> after
其中“i++;”相當於“i = i + 1;”包含了“i + 1”和“i =”兩個過程,不屬於原子操作,所以在多執行緒訪問該方法的時候是不安全的
當兩個執行緒同時獲取到i = 0的值時,如果此時都沒有執行到“i =”這個步驟的時候,那麼兩個執行緒等號右邊都是1,然後前後執行“i = 1” 這個操作,相當於i最終被兩次賦值為1,所以最終“i = 1”