JAVA高併發從內存分析數據不一致的原因

併發: 多線個線程操作相同的資源,保證線程安全,合理使用資源

高併發: 服務能短時間同時處理很多請求,提高程序性能

以下代碼,通過對共享變量進行累加操作,模擬200個線程,客戶端500個請求

    private static int threadTotal = 200;
    private static int clientTotal = 500;

    private static long count = 0;

    public static void main(String[] args) {
        ExecutorService exec = Executors.newCachedThreadPool();

        final Semaphore semaphore = new Semaphore(threadTotal);
        for (int index = 0; index < clientTotal; index++) {
            exec.execute(() -> {
                try {
                    semaphore.acquire();
                    add();
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });

        }
        exec.shutdown();
        log.info("count={}", count);
    }

    private static void add() {
        count++;
    }

多次運行程序,會發現每次計算的結果不一致,如果將threadTotal改成1,單個線程執行,多次運行的結果又會一致,

當JAVA程序多條線程執行主內存中的共享變量時,線程與線程之間是如何通信的呢?

假設A線程先執行,會從本地內存A中(抽象模型)取出更新過的共享變量副本刷新到主內存中去,

線程B會去主內存讀取線程A更新過的共享變量

假設上述代碼主內存中共享變量的值爲1,線程A和線程B同時執行,線程A從主內存讀取到的值是1,提取到自己的本地內存中進行+1的操作,將得到的結果2更新到主內存的共享變量

同時線程B,線程A從主內存拿到值爲1的同時,線程B也拿到了1,放入B的本地內存進行+1操作等到2,線程A將結果2更新到主內存的同時,線程B也將結果2更新到主內存,而不是先讀取線程A更新的2之後再重新計算!因此出現了錯誤

解決方案:增加同步的操作

同步的8種操作

lock(鎖定): 作用於主內存的變量,把一個變量標識爲一條線程獨佔狀態

unlock(解鎖):作用於主內存的變量,把一個處於鎖定狀態的變量釋放出來,釋放後的變量纔可以被其他線程鎖定

read(讀取):作用於主內存的變量,把一個變量值從主內存傳輸到線程的工作內存中,以便隨後的load動作使用

load(載入):作用域工作內存的變量,它把read操作從主內存中得到的變量值放入工作內存的變量副本中

user(使用):作用於工作內存的變量,把工作內存中的一個變量值傳遞給執行引擎

assign(賦值):作用於工作內存的變量,它把一個從執行引擎接收到的值賦值給工作內存的變量

store(存儲):作用於工作內存的變量,把工作內存中的一個變量的值傳送到主內存中,以便隨後的write的操作

write(寫入):作用於主內存的變量,它把store操作從工作內存中一個變量的值傳送到主內存的變量中

發佈了31 篇原創文章 · 獲贊 8 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章