Java AtomicInteger的用法


1、java.util.concurrent.atomic 的包里有AtomicBoolean, AtomicInteger,AtomicLong,AtomicLongArray,
AtomicReference等原子類的類,主要用於在高並發環境下的高效程序處理,來幫助我們簡化同步處理.

在Java語言中,++i和i++操作並不是線程安全的,在使用的時候,不可避免的會用到synchronized關鍵字。而AtomicInteger則通過一種線程安全的加減操作接口。

2、AtomicInteger的基本方法

創建一個AtomicInteger

  System.out.println(atomicInteger.get());


--->輸出 : 123

創建一個不傳值的,默認值為0

  AtomicInteger atomicInteger = new AtomicInteger();
  System.out.println(atomicInteger.get());
---->輸出: 0

獲取和賦值

atomicInteger.get(); //獲取當前值
atomicInteger.set(999); //設置當前值

atomicInteger.compareAndSet(expectedValue,newValue)

public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(0);
        System.out.println(atomicInteger.get());

        int expectedValue = 123;
        int newValue      = 234;
        Boolean b =atomicInteger.compareAndSet(expectedValue, newValue);
        System.out.println(b);
        System.out.println(atomicInteger);

    }

----》輸出結果為: 0 false 0


 public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(123);
        System.out.println(atomicInteger.get());

        int expectedValue = 123;
        int newValue      = 234;
        Boolean b =atomicInteger.compareAndSet(expectedValue, newValue);
        System.out.println(b);
        System.out.println(atomicInteger);

    }

-----》輸出結果為: 123 true  234

由上可知該方法表示,atomicInteger的值與expectedValue相比較,如果不相等,則返回false,
atomicInteger原有值保持不變;如果兩者相等,則返回true,atomicInteger的值更新為newValue

  • getAndAdd()方法與AddAndGet方法
AtomicInteger atomicInteger = new AtomicInteger(123);
        System.out.println(atomicInteger.get());  --123

        System.out.println(atomicInteger.getAndAdd(10)); --123 獲取當前值,並加10
        System.out.println(atomicInteger.get()); --133


        System.out.println(atomicInteger.addAndGet(10)); --143 獲取加10后的值,先加10
        System.out.println(atomicInteger.get()); --143

getAndDecrement()和DecrementAndGet()方法

AtomicInteger atomicInteger = new AtomicInteger(123);
        System.out.println(atomicInteger.get());   --123

        System.out.println(atomicInteger.getAndDecrement()); --123 獲取當前值並自減
        System.out.println(atomicInteger.get());  --122


        System.out.println(atomicInteger.decrementAndGet()); --121 先自減再獲取減1后的值
        System.out.println(atomicInteger.get()); --121
3、使用AtomicInteger,即使不用同步塊synchronized,最后的結果也是100,可用看出AtomicInteger的作用,用原子方式更新的int值。主要用於在高並發環境下的高效程序處理。使用非阻塞算法來實現並發控制。
public class Counter {

    public static AtomicInteger count = new AtomicInteger(0);

    public static void inc(){
        try{
            Thread.sleep(1); //延遲1毫秒

        }catch (InterruptedException e){ //catch住中斷異常,防止程序中斷
            e.printStackTrace();

        }
        count.getAndIncrement();//count值自加1
    }


    public static void main(String[] args) throws InterruptedException {


        final CountDownLatch latch = new CountDownLatch(100);

        for(int i=0;i<100;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Counter.inc();
                    latch.countDown();
                }
            }).start();
        }
        latch.await();

        System.out.println("運行結果:"+Counter.count);


    }
}

運行結果: 100

4、使用普通Integer

public class Counter {

    public volatile  static int count = 0;

    public static void inc(){
        try{
            Thread.sleep(1); //延遲1毫秒

        }catch (InterruptedException e){ //catch住中斷異常,防止程序中斷
            e.printStackTrace();

        }
        count++;//count值自加1
    }


    public static void main(String[] args) throws InterruptedException {


        final CountDownLatch latch = new CountDownLatch(100);

        for(int i=0;i<100;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Counter.inc();
                    latch.countDown();
                }
            }).start();
        }
        latch.await();

        System.out.println("運行結果:"+Counter.count);
   }
}
運行結果:98

5、如果在inc方法前面加個synchronized也能是線程安全的;

它用來修飾一個方法或者一個代碼塊的時候,能夠保證在同一時刻最多只有一個線程執行該段代碼。

import java.util.concurrent.CountDownLatch;

/**
 * created by guanguan  on 2017/10/23
 **/
public class Counter {

     public volatile static  Integer count = 0;

    public synchronized static void inc(){
        try{
            Thread.sleep(1); //延遲1毫秒

        }catch (InterruptedException e){ //catch住中斷異常,防止程序中斷
            e.printStackTrace();

        }
          count++;//count值自加1
    }


    public static void main(String[] args) throws InterruptedException {


        final CountDownLatch latch = new CountDownLatch(100);

        for(int i=0;i<100;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Counter.inc();
                    latch.countDown();
                }
            }).start();
        }
        latch.await();

        System.out.println("運行結果:"+Counter.count);


    }
}

運行結果:100

synchronized的使用說明:

一、當兩個並發線程訪問同一個對象object中的這個synchronized(this)同步代碼塊時,一個時間內只能有一個線程得到執行。另一個線程必須等待當前線程執行完這個代碼塊以后才能執行該代碼塊。

二、然而,當一個線程訪問object的一個synchronized(this)同步代碼塊時,另一個線程仍然可以訪問該object中的非synchronized(this)同步代碼塊。

三、尤其關鍵的是,當一個線程訪問object的一個synchronized(this)同步代碼塊時,其他線程對object中所有其它synchronized(this)同步代碼塊的訪問將被阻塞。

四、第三個例子同樣適用其它同步代碼塊。也就是說,當一個線程訪問object的一個synchronized(this)同步代碼塊時,它就獲得了這個object的對象鎖。結果,其它線程對該object對象所有同步代碼部分的訪問都被暫時阻塞。

五、以上規則對其它對象鎖同樣適用.

6、從上面的例子中我們可以看出:使用AtomicInteger是非常的安全的.而且因為AtomicInteger由硬件提供原子操作指令實現的。在非激烈競爭的情況下,開銷更小,速度更快。

java的關鍵域有3個

// setup to use Unsafe.compareAndSwapInt for updates  
private static final Unsafe unsafe = Unsafe.getUnsafe();  
private static final long valueOffset;  
private volatile int value; 

這里, unsafe是java提供的獲得對對象內存地址訪問的類,注釋已經清楚的寫出了,它的作用就是在更新操作時提供“比較並替換”的作用。實際上就是AtomicInteger中的一個工具。

valueOffset是用來記錄value本身在內存的便宜地址的,這個記錄,也主要是為了在更新操作在內存中找到value的位置,方便比較。

注意:value是用來存儲整數的時間變量,這里被聲明為volatile,就是為了保證在更新操作時,當前線程可以拿到value最新的值(並發環境下,value可能已經被其他線程更新了)。

這里,我們以自增的代碼為例,可以看到這個並發控制的核心算法:

源碼

 public final int updateAndGet(IntUnaryOperator updateFunction) {
        int prev, next;
        do {
            prev = get();
            next = updateFunction.applyAsInt(prev);
        } while (!compareAndSet(prev, next));
        return next;
    }

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM