1. 程式人生 > >a=a+1背後的內存模型和CPU高速緩存

a=a+1背後的內存模型和CPU高速緩存

變量 線程編程 臨時 一份 提高工作效率 的人 str 運行 結果

  學過JAVA的人都知道,程序運行過程中的臨時數據,都是從外部存儲設備調入內存(物理內存)中,再進行讀寫操作的。而計算機在執行程序時,對程序的每條指令都是在CPU中執行的,而指令的執行,勢必涉及到對數據的讀寫操作。

  於是就產生了這樣一個問題,CPU指令的執行速度是很快的,但是從內存中讀取和寫入數據的速度卻是比較慢的。如果對數據的任何操作,都需要CPU和內存打交道,而由於內存的讀取速度遠遠慢於CPU的執行速度,這樣就大大降低了CPU執行的效率,於是就有了CPU高速緩存的概念。

  CPU,CPU高速緩存,內存協同工作過程

  1、程序運行過程,會將所需要操作的業務數據加載到內存中,並復制一份到CPU的高速緩存中。

  2、CPU指令執行時,直接從CPU高速緩存中讀取和寫入數據,提高工作效率。

  3、CPU運算結束後,將結果寫入CPU高速緩存,此時再同步至內存中。

  

  多線程場景下a = a + 1的難題

  程序執行該代碼時,JVM進程中首先開啟一個線程,從外部存儲設備中加載class文件至內存中並賦予了a初始值,並將a值復制一份存儲至CPU高速緩存中。運算時,CPU指令首先從高速緩存中讀取a值,進行+1操作後將結果寫入高速緩存中,再由高速緩存同步至內存中,於是一個加法運算的全過程就順利完成了。

  這個代碼在單線程的場景中,是沒有任何問題的。但如果是運行在多核CPU的多線程場景下就會出問題了。

  在多核CPU下,每個線程都可能擁有自己獨立的CPU,每個線程運行時都有自己的CPU高速緩存,這樣就容易造成計算結果的臟數據。

  假設a在JVM加載初始化過程被賦值為0,線程A和B同時執行a = a + 1的操作,此時我們預期的結果可能都是a最終的結果為2。

  但是,如果線程A,B同時從內存中復制了a值至各自的CPU高速緩存中,A執行完了a = 1寫入自己線程的緩存,再同步回內存,B也如此。這樣一來,最終a的值就定格在了1,這是和預期結果所相悖的。也就是說,在多CPU,多線程編程的場景下,很有可能存在計算結果為臟數據的現象。

  為解決該難題,就需要使用volatile關鍵字對變量進行修飾了,至於volatile關鍵字為啥有此神奇功效,請看本博客的《深入剖析volatile關鍵字》。

  

a=a+1背後的內存模型和CPU高速緩存