本篇博文,主要集中併發編程的三個問題:可見性、原子性、有序性。數據庫
只講理論,不談如何解決。編程
說白了併發編程中的三個問題,就是先輩們給咱們這些後輩留下來的坑!緩存
相信大部分人都知道,一臺計算機的組成包括但不限於:CPU、內存、顯卡….安全
在這裏, 筆者將計算機中的組抽象成幾類,即:CPU、I/O設備、內存微信
有了以上三個分類,筆者接下來的文章就好寫了。(滑稽)多線程
講道理,在處理速度方面CPU >> 內存 >> I/O設備
。併發
這時候, 爲了充分發揮CPU的計算速度, 硬件方面則是在CPU和內存之間, 增長了一種叫高速緩存的技術。學習
總而言之,高速緩存的出現主要是爲了解決CPU運算速度與內存讀寫速度不匹配的矛盾。優化
固然, 在單核時代Cpu緩存並無出現數據一致性問題, 可是在多核時代就不同了。操作系統
在多核處理器中,因爲Cpu並不與內存直接打交道, 而是經過高速緩存。
同理, 內存也是並不直接與Cpu打交道,也是經過高速緩存與Cpu打交道。
緩存一致性問題以及解決方案,網上一搜一大堆,筆者在此就不作過多的敘述。
因此,只須要記住結論便可:
Cpu緩存不一致爲併發編程帶來----可見性問題。(結論)
在之前的印象中,說到原子性,筆者張口就是:原子操做是一個不可分割的總體, 該總體中的全部指令,要麼所有執行, 要麼所有不執行, 沒有中間狀態。
在此,筆者所寫的原子性概念,彷彿過於寬泛和縹緲。並且,原子性在不一樣的使用場景,也有可能含義並不相同。
接下來,咱們試着從數據庫事務和併發編程兩個方面來進行對比:
在數據庫中,原子性概念以下:
在併發編程中,原子性概念以下:
從上文中能夠看出,併發編程和數據庫二者之間的原子性概念有些類似。
都是強調,一個原子操做不能被打斷!!
因此,上下文切換給併發編程帶來——原子性問題。(結論)
講道理,在計算機語言中,高級語言的運行都須要經過編譯器轉換成機器語言,經過機器語言在計算機上運行。
那麼,在編譯器中爲了提升運行速度,會對內存訪問的有關操做(讀&寫)作一種優化,即指令的重排序。這種重排序在單線程環境下,不影響結果的正確性。可是,在多線程環境下可能會對結果的正確性產生影響。
指令的重排序,是形成併發編程的有序性問題的緣由。
編譯器帶來指令重排序,而指令重排序形成有序性問題。
編譯器優化—帶來—> 指令重排序—帶來—>有序性問題
因此,編譯器的優化給併發編程帶來—有序性問題!
最後,本篇博文,主要是對剛學習併發編程的朋友,提出併發編程的三個問題的概念。
說實話,筆者剛開始學的時候,並無想過想過原子、有序、可見性的形成緣由,直接通通死記硬背!
有時候想一想,以爲本身挺好笑的。
總之,讀者們要記住,整個Java併發包的設計與實現,都是爲了解決併發編程的可見、原子、有序三個問題。
接下來,筆者會嘗試着寫寫,Java是如何解決可見性、原子性和有序性的….