java.util.concurrent.atomic 包詳解

來源:互聯網
上載者:User

標籤:mic   jvm   icm   需要   float   10個   countdown   ring   getname   

Atomic包的作用:

方便程式員在多線程環境下,無鎖的進行原子操作

Atomic包核心:

Atomic包裡的類基本都是使用Unsafe實現的封裝類,核心操作是CAS原子操作

關於CAS

compare and swap,比較和替換技術,將預期值與當前變數的值比較(compare),如果相等則使用新值替換(swap)當前變數,否則不作操作;

現代CPU已廣泛支援CAS指令,如果不支援,那麼JVM將使用自旋鎖,與互斥鎖一樣,兩者都需先擷取鎖才能訪問共用資源,但互斥鎖會導致線程進入睡眠,而自旋鎖會一直迴圈等待直到擷取鎖;

另外,有一點需要注意的是CAS操作中的ABA問題,即將預期值與當前變數的值比較的時候,即使相等也不能保證變數沒有被修改過,因為變數可能由A變成B再變回A,解決該問題,可以給變數增加一個版本號碼,每次修改變數時版本號碼自增,比較的時候,同時比較變數的值和版本號碼即可

Atomic包主要提供四種原子更新方式
  • 原子方式更新基本類型
  • 原子方式更新數組
  • 原子方式更新引用
  • 原子方式更新欄位
原子方式更新基本類型

以下三個類是以原子方式更新基本類型

  • AtomicBoolean:原子更新布爾類型。
  • AtomicInteger:原子更新整型。
  • AtomicLong:原子更新長整型。

以AtomicInteger為例:

package cn.com.example.concurrent.atomic;import java.util.concurrent.atomic.AtomicInteger;/** * Created by Jack on 2017/1/7. */public class AtomicIntegerTest extends Thread {    private AtomicInteger atomicInteger;    public AtomicIntegerTest(AtomicInteger atomicInteger) {        this.atomicInteger = atomicInteger;    }    @Override    public void run() {        int i = atomicInteger.incrementAndGet();        System.out.println("generated  out number:" + i);    }    public static void main(String[] args) {        AtomicInteger counter = new AtomicInteger();        for (int i = 0; i < 10; i++) {//10個線程            new AtomicIntegerTest(counter).start();        }    }}

輸出:

generated  out number:1generated  out number:2generated  out number:3generated  out number:4generated  out number:5generated  out number:6generated  out number:7generated  out number:8generated  out number:9generated  out number:10

注意:Atomic包提供了三種基本類型的原子更新,剩餘的Java的基本類型還有char,float和double等,其更新方式可以參考AtomicBoolean的思路來現,AtomicBoolean是把boolean轉成整型再調用compareAndSwapInt進行CAS來實現的,類似的short和byte也可以轉成整形,float和double可以利用Float.floatToIntBits,Double.doubleToLongBits轉成整形和長整形進行相應處理

原子方式更新數組

以下三個類是以原子方式更新數組

  • AtomicIntegerArray:原子更新整型數組裡的元素。
  • AtomicLongArray:原子更新長整型數組裡的元素。
  • AtomicReferenceArray:原子更新參考型別數組裡的元素

以AtomicIntegerArray為例,其方法與AtomicInteger很像,多了個數組下標索引

package cn.com.example.concurrent.atomic;import java.util.concurrent.CountDownLatch;import java.util.concurrent.atomic.AtomicIntegerArray;/** * Created by Jack on 2017/1/7. */public class AtomicIntegerArrayTest {    private static int threadCount = 1000;    private static CountDownLatch countDown = new CountDownLatch(threadCount);    static int[] values = new int[10];    static AtomicIntegerArray ai = new AtomicIntegerArray(values);    private static class Counter implements Runnable {        @Override        public void run() {            for (int i = 0; i < 100; i++) {                for (int j = 0; j < 10; j++) {//所有元素+1                    ai.getAndIncrement(j);                }            }            countDown.countDown();        }    }    public static void main(String[] args) throws InterruptedException {        Thread[] threads = new Thread[threadCount];        for (int i = 0; i < threadCount; i++) {            threads[i] = new Thread(new Counter());        }        for (int i = 0; i < threadCount; i++) {            threads[i].start();        }        countDown.await();        for (int i = 0; i < 10; i++) {            System.out.println(ai.get(i) + " ");        }        System.out.println();        for (int i = 0; i < 10; i++) {            System.out.println(values[i] + " ");        }    }}

輸出:

100000 100000 100000 100000 100000 100000 100000 100000 100000 100000 0 0 0 0 0 0 0 0 0 0 

需要注意的是,數組value通過構造方法傳遞進去,然後AtomicIntegerArray會將當前數組複製一份,所以當AtomicIntegerArray對內部的數組元素進行修改時,不會影響傳入的數組。

原子方式更新引用

以下三個類是以原子方式更新引用,與其它不同的是,更新引用可以更新多個變數,而不是一個變數

  • AtomicReference:原子更新參考型別。
  • AtomicReferenceFieldUpdater:原子更新參考型別裡的欄位。
  • AtomicMarkableReference:原子更新帶有標記位的參考型別。

以AtomicReference為例

package cn.com.example.concurrent.atomic;import java.util.concurrent.atomic.AtomicReference;/** * Created by Jack on 2017/1/7. */public class AtomicReferenceTest {    public static void main(String[] args) {        // 建立兩個Person對象,它們的id分別是101和102。        Person p1 = new Person(101);        Person p2 = new Person(102);        // 建立AtomicReference對象,初始化它的值為p1對象        AtomicReference ar = new AtomicReference(p1);        // 通過CAS設定ar。如果ar的值為p1的話,則將其設定為p2。        ar.compareAndSet(p1, p2);        Person p3 = (Person) ar.get();        System.out.println("p3 is " + p3);        System.out.println("p3.equals(p1)=" + p3.equals(p1));    }}class Person {    volatile long id;    public Person(long id) {        this.id = id;    }    public String toString() {        return "id:" + id;    }}

輸出:

p3 is id:102p3.equals(p1)=false

建立AtomicReference對象ar時,將它初始化為p1。
緊接著,通過CAS函數對它進行設定。如果ar的值為p1的話,則將其設定為p2。
最後,擷取ar對應的對象,並列印結果。p3.equals(p1)的結果為false,這是因為Person並沒有覆蓋equals()方法,而是採用繼承自Object.java的equals()方法;而Object.java中的equals()實際上是調用"=="去比較兩個對象,即比較兩個對象的地址是否相等。

原子方式更新欄位

以下三個類是以原子方式更新欄位

  • AtomicIntegerFieldUpdater:原子更新整型欄位的更新器。
  • AtomicLongFieldUpdater:原子更新長整型欄位的更新器。
  • AtomicStampedReference:原子更新帶有版本號碼的參考型別,用於解決使用CAS進行原子更新時,可能出現的ABA問題。

以AtomicIntegerFieldUpdater為例

package cn.com.example.concurrent.atomic;import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;/** * Created by Jack on 2017/1/7. */public class AtomicIntegerFieldUpdaterTest {    // 建立原子更新器,並設定需要更新的對象類和對象的屬性    private static AtomicIntegerFieldUpdater<User> a = AtomicIntegerFieldUpdater.newUpdater(User.class, "old");    public static void main(String[] args) throws InterruptedException {        // 設定柯南的年齡是10歲        User conan = new User("conan", 10);        // 柯南長了一歲,但是仍然會輸出舊的年齡        System.out.println(a.getAndIncrement(conan));        // 輸出柯南現在的年齡        System.out.println(a.get(conan));    }    public static class User {        private String name;        public volatile int old;        public User(String name, int old) {            this.name = name;            this.old = old;        }        public String getName() {            return name;        }        public int getOld() {            return old;        }    }}

輸出:

1011

注意: old 需要聲明為 volatile

java.util.concurrent.atomic 包詳解

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.