1. 程式人生 > >操作的原子性與執行緒安全

操作的原子性與執行緒安全

本案例來源於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”

歡迎有興趣的