竞态条件与临界区
2019獨角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
在同一程序中運行多個線程本身不會導(dǎo)致問題,問題在于多個線程訪問了相同的資源。如,同一內(nèi)存區(qū)(變量,數(shù)組,或?qū)ο?#xff09;、系統(tǒng)(數(shù)據(jù)庫,web services等)或文件。實際上,這些問題只有在一或多個線程向這些資源做了寫操作時才有可能發(fā)生,只要資源沒有發(fā)生變化,多個線程讀取相同的資源就是安全的。
多線程同時執(zhí)行下面的代碼可能會出錯:
| 1 | public?class?Counter { |
| 2 | ????protected?long?count =?0; |
| 3 | ????public?void?add(long?value){ |
| 4 | ????????this.count =?this.count + value;?? |
| 5 | ????} |
| 6 | } |
想象下線程A和B同時執(zhí)行同一個Counter對象的add()方法,我們無法知道操作系統(tǒng)何時會在兩個線程之間切換。JVM并不是將這段代碼視為單條指令來執(zhí)行的,而是按照下面的順序:
從內(nèi)存獲取 this.count 的值放到寄存器 將寄存器中的值增加value 將寄存器中的值寫回內(nèi)存觀察線程A和B交錯執(zhí)行會發(fā)生什么:
this.count = 0;A: 讀取 this.count 到一個寄存器 (0)B: 讀取 this.count 到一個寄存器 (0)B: 將寄存器的值加2B: 回寫寄存器值(2)到內(nèi)存. this.count 現(xiàn)在等于 2A: 將寄存器的值加3A: 回寫寄存器值(3)到內(nèi)存. this.count 現(xiàn)在等于 3兩個線程分別加了2和3到count變量上,兩個線程執(zhí)行結(jié)束后count變量的值應(yīng)該等于5。然而由于兩個線程是交叉執(zhí)行的,兩個線程從內(nèi)存中讀出的初始值都是0。然后各自加了2和3,并分別寫回內(nèi)存。最終的值并不是期望的5,而是最后寫回內(nèi)存的那個線程的值,上面例子中最后寫回內(nèi)存的是線程A,但實際中也可能是線程B。如果沒有采用合適的同步機制,線程間的交叉執(zhí)行情況就無法預(yù)料。
競態(tài)條件 & 臨界區(qū)
當(dāng)兩個線程競爭同一資源時,如果對資源的訪問順序敏感,就稱存在競態(tài)條件。導(dǎo)致競態(tài)條件發(fā)生的代碼區(qū)稱作臨界區(qū)。上例中add()方法就是一個臨界區(qū),它會產(chǎn)生競態(tài)條件。在臨界區(qū)中使用適當(dāng)?shù)耐骄涂梢员苊飧倯B(tài)條件。
轉(zhuǎn)載于:https://my.oschina.net/Chaos777/blog/267532
總結(jié)
- 上一篇: 循环不变式
- 下一篇: php怎么将json数据转化为数组类型