Java併發之原子變量及CAS算法-上篇

Java併發之原子變量及CAS算法-上篇

Java併發之原子變量及CAS算法-上篇

概述

本文主要講在Java併發編程的時候,如果保證變量的原子性,在JDK提供的類中是怎麼保證變量原子性的呢?。對應Java中的包是:java.util.concurrent.atomic包下。因為涉及到了CAS算法,需要對CAS算法講解及CAS算法三個問題怎麼解決以及和Synchroized比較。文章比較長,所以就分為上下兩個篇幅講解。本文是上篇《Java併發之原子變量及CAS算法-上篇》

本文是《凱哥分享Java併發編程之J.U.C包講解》系列教程中的一篇。如果想系統學習,建議從第一篇開始看。

原子變量案例

在Java中有一種寫法:int i = 10; i++ 這種寫法。

我們先來看看:

Java併發之原子變量及CAS算法-上篇

輸入的是0還是1呢 ?

I++輸出0的原因分析

答案是:0。為什麼呢?凱哥把編譯後的class文件反編譯,咱們看:

Java併發之原子變量及CAS算法-上篇

說明:i的操作是i++;y的操作是++y.

從反編譯後的代碼,我們可以看到i++在JVM中的操作,總共分三步:

第一步:聲明變量var10000 ,然後將i賦值給var10000,此時var10000的值是0;

第二步:聲明變量var3 然後把i+1 賦值給var3,此時,var3的值等於1了;

第三步:將變量var10000的值又賦值給了i,此時因為var10000的值是0,所以i的值也是0

所以在sysout(i)的時候,就輸出了0.

我們分析上面1,2,3步驟,可以發現。其實i++執行的是:讀取-修改-重寫 三個操作。

既然讀寫操作,就會涉及到變量原子性。測試在多線程下變量原子性

測試多線程下的變量原子性

那麼,如果我們把對i的操作放到多個線程中操作結果會是什麼樣的呢?

線程操作I的代碼:

Java併發之原子變量及CAS算法-上篇

開啟十個線程同時操作i的代碼:

Java併發之原子變量及CAS算法-上篇

我們來看看運行結果:

Java併發之原子變量及CAS算法-上篇

從運行結果中,我們可以看到,線程Thread-5和線程Thread-8的值是一樣的。

根據上面運行的場景,我們發現,變量i其實是十個線程中的共享變量。從運行的結果來看,多個線程操作後,結果出問題了。

不同線程在內存中運行模擬圖:

Java併發之原子變量及CAS算法-上篇

線程1;線程2;以及主線程之間運行關係,可以詳見凱哥上一篇文章:《Java併發之內存可見性問題怎麼解決》。這篇文章詳細講解了怎麼關係。

已經看過凱哥上一篇文章或者是知道volatile關鍵字的朋友可能要說,這不就是線程之間變量可見性問題嘛。使用volatile關鍵字修飾i就可以了。真的可以了嗎?

我們修改程序,用volatile來修飾,看看運行結果:

使用volatile關鍵字是否能解決多線程情況下變量原子性呢?

用volatile來修飾變量:

private volatile int shardData = 0;

運行結果:

Java併發之原子變量及CAS算法-上篇

我們發現,就算使用volatile關鍵字修飾了,依然存在多線程下變量原子性的問題。

怎麼解決這種併發下變量原子性問題呢?

Java的atomic包

在jdk1.5以後,Java為我們提供了一個常用的原子變量。都在:java.util.concureent.atomic包下。我們來看看,都有哪些:

Java併發之原子變量及CAS算法-上篇


Java併發之原子變量及CAS算法-上篇

Java併發之原子變量及CAS算法-上篇

從JDK的API文檔中(凱哥使用的是JDK1.8的API)我們可以看到常用的原子性變量。

怎麼保證原子性呢?

那麼,在atomic包下的這些類怎麼保證原子性呢?

1:該包下的變量都是使用volatile關鍵字來修飾。

解決了多線程之間變量可見性。

Int類型的原子性對象AtomicInteger對象中:

Java併發之原子變量及CAS算法-上篇

用於對象的AtomicReference對象中:


Java併發之原子變量及CAS算法-上篇

都是使用volat關鍵字修飾的。

2:使用CAS算法

保持了變量的原子性

總結:

在Java的JDK中提供了concurrent.atomic包,使用這個包下的對象創建的變量就能保證原子性。

保證原子性的策略:

1:變量都是用Volatile關鍵字修飾。來保證內存可見性

2:使用CAS算法,來保證原子性。

Java併發之原子變量及CAS算法-上篇

下篇預告:

在下一篇文章中,我們主要講解CAS算法原理及CAS算法會參數哪些問題(三個問題)?JDK是怎麼解決的?修改i++使其成為具有原子性變量怎麼實現。


分享到:


相關文章: