本文爲轉載學習html
原文連接:http://tutorials.jenkov.com/java-concurrency/race-conditions-and-critical-sections.htmljava
譯文連接:http://ifeve.com/race-conditions-and-critical-sections/web
在同一程序中運行多個線程自己不會致使問題,問題在於多個線程訪問了相同的資源。如,同一內存區(變量,數組,或對象)、系統(數據庫,web services等)或文件。實際上,這些問題只有在一或多個線程向這些資源作了寫操做時纔有可能發生,只要資源沒有發生變化,多個線程讀取相同的資源就是安全的。數據庫
多線程同時執行下面的代碼可能會出錯:數組
public class Counter { protected long count = 0; public void add(long value){ this.count = this.count + value; } }
想象下線程A和B同時執行同一個Counter對象的add()方法,咱們沒法知道操做系統什麼時候會在兩個線程之間切換。JVM並非將這段代碼視爲單條指令來執行的,而是按照下面的順序:安全
從內存獲取 this.count 的值放到寄存器 將寄存器中的值增長value 將寄存器中的值寫回內存
觀察線程A和B交錯執行會發生什麼:多線程
this.count = 0; A: 讀取 this.count 到一個寄存器 (0) B: 讀取 this.count 到一個寄存器 (0) B: 將寄存器的值加2 B: 回寫寄存器值(2)到內存. this.count 如今等於 2 A: 將寄存器的值加3 A: 回寫寄存器值(3)到內存. this.count 如今等於 3
兩個線程分別加了2和3到count變量上,兩個線程執行結束後count變量的值應該等於5。然而因爲兩個線程是交叉執行的,兩個線程從內存中讀出的初始值都是0。而後各自加了2和3,並分別寫回內存。最終的值並非指望的5,而是最後寫回內存的那個線程的值,上面例子中最後寫回內存的是線程A,但實際中也多是線程B。若是沒有采用合適的同步機制,線程間的交叉執行狀況就沒法預料。學習
當兩個線程競爭同一資源時,若是對資源的訪問順序敏感,就稱存在競態條件。致使競態條件發生的代碼區稱做臨界區。上例中add()方法就是一個臨界區,它會產生競態條件。在臨界區中使用適當的同步就能夠避免競態條件。this