做者:畢來生
微信:878799579
一、什麼是原子變量?
原子變量保證了該變量的全部操做都是原子的,不會由於多線程的同時訪問而致使髒數據的讀取問題。java
二、經過synchronized保證原子操做
三、Atomic之AtomicInteger源碼分析
java.util.concurrent.atomic包下幫助咱們提供了不少原子性的支持,請參考下圖微信
AtomicReference和AtomicReferenceArray:基於引用類型多線程
構造方法以下併發
private volatile int value; /** * Creates a new AtomicInteger with the given initial value. * * @param initialValue the initial value */ public AtomicInteger(int initialValue) { value = initialValue; } /** * Creates a new AtomicInteger with initial value {@code 0}. */ public AtomicInteger() { }
若是經過構造方法設置原子變量。如不設置初始值則會默認初始化爲0。ide
如下爲方法爲AtomicInteger基於原子操做經常使用方法源碼分析
//獲取當前原子變量中的值併爲其設置新值 public final int getAndSet(int newValue) //比較當前的value是否等於expect,若是是設置爲update並返回true,不然返回false public final boolean compareAndSet(int expect, int update) //獲取當前的value值並自增一 public final int getAndIncrement() //獲取當前的value值並自減一 public final int getAndDecrement() //獲取當前的value值併爲value加上delta public final int getAndAdd(int delta)
四、實戰演練
在多線程下。我但願對num = 0;進行自增,10個線程,每一個線程對變量自增10000次。結果應該是100000纔對。atom
首先咱們先來一個錯誤示範:spa
package org.bilaisheng.juc; /** * @Author: bilaisheng * @Wechat: 878799579 * @Date: 2019/1/1 21:58 * @Todo: AtomicInteger 原子性錯誤示範。僅演示使用 * @Version : JDK11 , IDEA2018 */ public class AtomicIntegerErrorTest { // 舉例10條線程併發,實際條數請參考本身場景 private static final int THREAD_COUNT = 10; private static int num = 0; public static void main(String[] args) { Thread[] threads = new Thread[THREAD_COUNT]; for (int i = 0; i < THREAD_COUNT; i++) { threads[i] = new Thread(new Runnable() { @Override public void run() { // 此處設置10000.過小看不到效果。請酌情設置 for (int j = 1; j <=10000 ; j++) { // 如想要看到結果請放開下行註釋 //System.out.println(Thread.currentThread().getName() +" num = "+num); num++ ; } } }); threads[i].start(); } System.out.println(Thread.currentThread().getName()); System.out.println(Thread.activeCount()); while (Thread.activeCount()>2){ Thread.yield(); } System.out.println(num); } }
運行結果舉例兩張以下圖所示。每次運行結果都不相同線程
接下來咱們的AtomicInteger就該登場了3d
package org.bilaisheng.juc; import java.util.concurrent.atomic.AtomicInteger; /** * @Author: bilaisheng * @Wechat: 878799579 * @Date: 2019/1/1 23:02 * @Todo: * @Version : JDK11 , IDEA2018 */ public class AtomicIntegerTest { private static final int THREADS_CONUT = 10; public static AtomicInteger num = new AtomicInteger(0); public static void main(String[] args) { Thread[] threads = new Thread[THREADS_CONUT]; for (int i = 0; i < threads.length; i++) { threads[i] = new Thread(new Runnable() { @Override public void run() { // 此處設置10000.過小看不到效果。請酌情設置 for (int j = 1; j <=10000 ; j++) { // 如想要看到結果請放開下行註釋 //System.out.println(Thread.currentThread().getName() +" num = "+num); num.incrementAndGet(); } } }); threads[i].start(); } while (Thread.activeCount() > 2) { Thread.yield(); } System.out.println(num); } }
結果是無論怎麼運行結果都和預期下相同。運行結果以下圖:
五、 Volatile能夠保證變量原子性嗎?
咱們先來看一下下面兩行代碼
private volatile long num = 4642761357212574643L; private volatile double amt= 4642761357212574643.23165421354;
如上代碼並不能保證num以及amt兩個變量就是原子性的,在32位處理器中 哪怕是經過volatile關鍵字進行修飾也沒法保證變量原子性。由於在32位系統下。若是出現了多線程同時操做某個變量。這個變量正在被線程a進行修改。此時線程b訪問此變量。可能只獲取到該變量的前32位,故可能會致使原子性失效。致使不可預知的狀況以及錯誤。若是本地和生產均爲64位處理器。請忽略以上廢話。