什么是競態條件
官方的定義是如果程序運行順序的改變會影響最終結果,這就是一個競態條件(race condition).
理解競態條件首先要知道程序運行不一定是線性的。初學編程的時候都是從“面向過程編程“開始的,一條一條指令打下來,期待着他們會順序執行。debug的使用也加深了這一認識。不過事實上如果兩條緊挨着的指令沒有依賴關系,jvm是有可能將他們的運行順序倒轉的。當然這是題外話,最顯著的“不按順序執行“的例子還是多線程程序。
Runnable r1 = () -> { // do something };
Runnable r2 = () -> { // do another thing };
new Thread(r1).start();
new Thread(r2).start();
上述程序定義了兩個Runnable實例,並用它們新建兩個線程,雖然r1先於r2開始,但他們內部的代碼誰先誰后就不由而知了。
如果一段程序運行多次的結果不一致(排除生成隨機數的情況),那這就可能是競態條件的體現。比如最典型的例子,兩個線程同時把一個類的靜態成員做50詞自增加1的操作,即
SomeClass.someMember++;
寫在兩個線程中,都運行50次,運行結束以后用主線程去取這個變量的值幾乎不可能是100. 有的時候是97,有的時候是98,這是用來說明競態條件的最有效例子。
競態條件 & 臨界區
當兩個線程競爭同一資源時,如果對資源的訪問順序敏感,就稱存在競態條件。導致競態條件發生的代碼區稱作臨界區。