日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

Java中12个原子操作类

發(fā)布時間:2025/3/12 java 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java中12个原子操作类 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Java 從 JDK 1.5 開始提供了 java.util.concurrent.atomic 包(以下簡稱Atomic包),這個包中的 原子操作類 提供了一種用法簡單、性能高效、線程安全地更新一個變量的方式。

因為變量的類型有很多種,所以在 Atomic 包里一共提供了 12個 類,屬于以下 4 種類型的原子更新方式:

原子更新基本類型。

AtomicBoolean:原子更新布爾類型。

AtomicInteger:原子更新整型。

AtomicLong:原子更新長整型。

原子更新數(shù)組。

AtomicIntegerArray:原子更新整型數(shù)組里的元素。

AtomicLongArray:原子更新長整型數(shù)組里的元素。

AtomicReferenceArray:原子更新引用類型數(shù)組里的元素。

原子更新引用。

AtomicReference:原子更新對象引用。

AtomicMarkableReference:原子更新帶有標(biāo)記位的對象引用。

AtomicStampedReference:原子更新帶有版本號的對象引用。

原子更新屬性(字段)。

AtomicIntegerFieldUpdater:原子更新volatile修飾的整型的字段的更新器。

AtomicLongFieldUpdater:原子更新volatile修飾的長整型字段的更新器。

AtomicReferenceFieldUpdater:原子更新volatile修飾的引用類型里的字段的更新器。

Atomic 包里的類基本都是使用 Unsafe 實現(xiàn)的包裝類。

原子更新基本類型

AtomicBoolean:原子更新布爾類型。

AtomicInteger:原子更新整型。

AtomicLong:原子更新長整型。

以上3個類提供的方法幾乎一模一樣,所以本節(jié)僅以 AtomicInteger 為例進(jìn)行講解。

AtomicInteger 的常用方法如下:

int addAndGet(int delta):以原子方式將輸入的數(shù)值與實例中的值(AtomicInteger 里的 value)相加,并返回結(jié)果。

boolean compareAndSet(int expect,int update):如果輸入的數(shù)值等于預(yù)期值,則以原子方式將該值設(shè)置為輸入的值。

int getAndIncrement():以原子方式將當(dāng)前值加1,注意,這里返回的是自增前的值。

void lazySet(int newValue):最終會設(shè)置成 newValue,使用 lazySet 設(shè)置值后,可導(dǎo)致其他線程在之后的一小段時間內(nèi)還是可以讀到舊的值。

int getAndSet(int newValue):以原子方式設(shè)置為 newValue 的值,并返回舊值。

示例

public static void main(String[] args) {AtomicInteger ai = new AtomicInteger(2);System.out.println("ai.get() = " + ai.get());System.out.println("ai.addAndGet(5) = " + ai.addAndGet(5));System.out.println("ai.get() = " + ai.get());System.out.println("ai.compareAndSet(ai.get(), 10) = " + ai.compareAndSet(ai.get(), 10));System.out.println("ai.get() = " + ai.get());System.out.println("ai.getAndIncrement() = " + ai.getAndIncrement());System.out.println("ai.get() = " + ai.get());ai.lazySet(8);System.out.println("ai.lazySet(8)");System.out.println("ai.get() = " + ai.get());System.out.println("ai.getAndSet(5) = " + ai.getAndSet(5));System.out.println("ai.get() = " + ai.get()); }

輸出

ai.get() = 2 ai.addAndGet(5) = 7 ai.get() = 7 ai.compareAndSet(ai.get(), 10) = true ai.get() = 10 ai.getAndIncrement() = 10 ai.get() = 11 ai.lazySet(8) ai.get() = 8 ai.getAndSet(5) = 8 ai.get() = 5

AtomicInteger 的 getAndIncrement()方法:

public final int getAndIncrement() {for (; ; ) {int current = get();int next = current + 1;if (compareAndSet(current, next)) {return current;}} } public final boolean compareAndSet(int expect, int update) {return unsafe.compareAndSwapInt(this, valueOffset, expect, update); }

for 循環(huán)體的先取得 AtomicInteger 里存儲的數(shù)值

對 AtomicInteger 的當(dāng)前數(shù)值進(jìn)行 +1 操作,

關(guān)鍵是調(diào)用 compareAndSet 方法來進(jìn)行原子更新操作,該方法先檢查 當(dāng)前數(shù)值是否等于current ?

等于意味著 AtomicInteger 的值沒有被其他線程修改過,則將 AtomicInteger 的當(dāng)前數(shù)值更新成 next的值。如果不等 compareAndSet 方法會返回 false,程序會進(jìn)入 for 循環(huán)重新進(jìn)行 compareAndSet 操作。

Atomic 包提供了 3 種基本類型的原子更新,但是 Java 的基本類型里還有 char、float 和 double 等。

那么問題來了,如何原子的更新其他的基本類型呢?

Atomic包里的類基本都是使用 Unsafe 實現(xiàn)的,讓我們一起看一下Unsafe的源碼:

/*** 如果當(dāng)前數(shù)值是expected,則原子的將Java變量更新成x** @return 如果更新成功則返回true*/ public final native boolean compareAndSwapObject(Object o, long offset,Object expected, Object x);public final native boolean compareAndSwapInt(Object o, long offset,int expected, int x);public final native boolean compareAndSwapLong(Object o, long offset,long expected, long x);

綜合上述代碼,我們可以發(fā)現(xiàn) Unsafe 只提供了 3 種 CAS 方法:compareAndSwapObject、compareAndSwapInt 和 compareAndSwapLong,再看 AtomicBoolean 源碼,發(fā)現(xiàn)它是先把 Boolean 轉(zhuǎn)換成 整型,再使用 compareAndSwapInt 進(jìn)行 CAS,所以原子更新 char、float 和 double 變量也可以用類似的思路來實現(xiàn)。

原子更新數(shù)組

AtomicIntegerArray:原子更新整型數(shù)組里的元素。

AtomicLongArray:原子更新長整型數(shù)組里的元素。

AtomicReferenceArray:原子更新引用類型數(shù)組里的元素。

以上幾個類提供的方法幾乎一樣,所以僅以 AtomicIntegerArray 為例進(jìn)行介紹:
AtomicIntegerArray 類主要是提供原子的方式更新數(shù)組里的整型。

常用方法如下:

int addAndGet(int i,int delta):以原子方式將輸入值與數(shù)組中索引i的元素相加。boolean compareAndSet(int i,int expect,int update):如果當(dāng)前值等于預(yù)期值,則以原子方式將數(shù)組位置i的元素設(shè)置成update值。

示例

public static void main(String[] args) {int[] value = new int[]{1, 2};AtomicIntegerArray ai = new AtomicIntegerArray(value);System.out.println("ai.getAndSet(0, 3)");ai.getAndSet(0, 3);System.out.println("ai.get(0) = " + ai.get(0));System.out.println("value[0] = " + value[0]);ai.compareAndSet(1, 2, 5);System.out.println("ai.compareAndSet(1, 2, 5)");System.out.println("ai.get(1) = " + ai.get(1)); }

輸出

ai.getAndSet(0, 3) ai.get(0) = 3 value[0] = 1 ai.compareAndSet(1,2,5) ai.get(1) = 5

注意:數(shù)組value通過構(gòu)造方法傳遞進(jìn)去,然后AtomicIntegerArray會將當(dāng)前數(shù)組復(fù)制一份,所以當(dāng)AtomicIntegerArray對內(nèi)部的數(shù)組元素進(jìn)行 修改 時,不會影響傳入的數(shù)組。

原子更新引用

AtomicReference:原子更新對象引用。

AtomicMarkableReference:原子更新帶有標(biāo)記位的對象引用。

AtomicStampedReference:原子更新帶有版本號的對象引用。該類將整數(shù)值與引用關(guān)聯(lián)起來,可用于原子的更新數(shù)據(jù)和數(shù)據(jù)的版本號,可以解決使用 CAS 進(jìn)行原子更新時可能出現(xiàn)的 ABA問題。

我們以AtomicReference為例進(jìn)行介紹。

示例

public class AtomicReferenceTest {public static AtomicReference<User> atomicUserRef = newAtomicReference<User>();public static void main(String[] args) {User user = new User("103style", 20);atomicUserRef.set(user);System.out.println("atomicUserRef.get() = " + atomicUserRef.get().toString());User updateUser = new User("xiaoke", 22);atomicUserRef.compareAndSet(user, updateUser);System.out.println("atomicUserRef.compareAndSet(user, updateUser);");System.out.println("atomicUserRef.get() = " + atomicUserRef.get().toString());}static class User {private String name;private int age;public User(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public int getAge() {return age;}@Overridepublic String toString() {return "name='" + name + ", age=" + age;}} }

輸出

atomicUserRef.get() = name='103style, age=20 atomicUserRef.compareAndSet(user, updateUser); atomicUserRef.get() = name='xiaoke, age=22

原子更新屬性(字段)

AtomicIntegerFieldUpdater:原子更新volatile修飾的整型的字段的更新器。

AtomicLongFieldUpdater:原子更新volatile修飾的長整型字段的更新器。

AtomicReferenceFieldUpdater:原子更新volatile修飾的引用類型里的字段的更新器。

要想原子地更新字段類需要兩步:

因為原子更新字段類都是抽象類,每次使用的時候必須使用靜態(tài)方法newUpdater()創(chuàng)建一個更新器,并且需要設(shè)置想要更新的類和屬性。更新類的字段(屬性)必須使用public volatile修飾符。

我們以AstomicIntegerFieldUpdater 為例進(jìn)行講解。

示例

public class AtomicIntegerFieldUpdaterTest {public static void main(String[] args) {// 創(chuàng)建原子更新器,并設(shè)置需要更新的對象類和對象的屬性AtomicIntegerFieldUpdater<User> a = AtomicIntegerFieldUpdater.newUpdater(User.class, "age");// 設(shè)置柯南的年齡是10歲User conan = new User("conan", 10);// 柯南長了一歲,但是仍然會輸出舊的年齡System.out.println(a.getAndIncrement(conan));// 輸出柯南現(xiàn)在的年齡System.out.println(a.get(conan));}public static class User {public volatile int age;private String name;public User(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public int getAge() {return age;}} }

輸出

10 11

了解更多歡迎點(diǎn)贊關(guān)注的喲!!!

總結(jié)

以上是生活随笔為你收集整理的Java中12个原子操作类的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。