在過去單cpu時代,單任務在一個時間點隻能執行單一程式。之後發展到多任務階段,計算機能在同一時間點并行執行多任務或多程序。雖然并不是真正意
義上的“同一時間點”,而是多個任務或程序共享一個cpu,并交由作業系統來完成多任務間對cpu的運作切換,以使得每個任務都有機會獲得一定的時間片運
行。
随着多任務對軟體開發者帶來的新挑戰,程式不在能假設獨占所有的cpu時間、所有的記憶體和其他計算機資源。一個好的程式榜樣是在其不再使用這些資源時對其進行釋放,以使得其他程式能有機會使用這些資源。
再後來發展到多線程技術,使得在一個程式内部能擁有多個線程并行執行。一個線程的執行可以被認為是一個cpu在執行該程式。當一個程式運作在多線程下,就好像有多個cpu在同時執行該程式。
多線程比多任務更加有挑戰。多線程是在同一個程式内部并行執行,是以會對相同的記憶體空間進行并發讀寫操作。這可能是在單線程程式中從來不會遇到的問
題。其中的一些錯誤也未必會在單cpu機器上出現,因為兩個線程從來不會得到真正的并行執行。然而,更現代的計算機伴随着多核cpu的出現,也就意味着不
同的線程能被不同的cpu核得到真正意義的并行執行。
如果一個線程在讀一個記憶體時,另一個線程正向該記憶體進行寫操作,那進行讀操作的那個線程将獲得什麼結果呢?是寫操作之前舊的值?還是寫操作成功之後
的新值?或是一半新一半舊的值?或者,如果是兩個線程同時寫同一個記憶體,在操作完成後将會是什麼結果呢?是第一個線程寫入的值?還是第二個線程寫入的值?
還是兩個線程寫入的一個混合值?是以如沒有合适的預防措施,任何結果都是可能的。而且這種行為的發生甚至不能預測,是以結果也是不确定性的。
java是最先支援多線程的開發的語言之一,java從一開始就支援了多線程能力,是以java開發者能常遇到上面描述的問題場景。這也是我想為java并發技術而寫這篇系列的原因。作為對自己的筆記,和對其他java開發的追随者都可獲益的。
該系列主要關注java多線程,但有些在多線程中出現的問題會和多任務以及分布式系統中出現的存在類似,是以該系列會将多任務和分布式系統方面作為參考,是以叫法上稱為“并發性”,而不是“多線程”。