哪個(gè)建立網(wǎng)站好小程序開發(fā)
目錄
1. 什么是原子操作
1.1?原子類的作用
1.2?原子類的常見(jiàn)操作
原子類的使用注意事項(xiàng)
并發(fā)編程是現(xiàn)代計(jì)算機(jī)應(yīng)用中不可或缺的一部分,而在并發(fā)編程中,處理共享資源的并發(fā)訪問(wèn)是一個(gè)重要的問(wèn)題。為了避免多線程訪問(wèn)共享資源時(shí)出現(xiàn)競(jìng)態(tài)條件(Race Condition)等問(wèn)題,Java提供了一組原子類(Atomic Classes)來(lái)支持線程安全的操作。
1. 什么是原子操作
在并發(fā)編程中,原子操作是不可被中斷的一個(gè)或一系列操作,要么全部執(zhí)行成功,要么全部不執(zhí)行,不會(huì)出現(xiàn)部分執(zhí)行的情況。原子操作能夠保證在多線程環(huán)境下,對(duì)共享資源的操作不會(huì)相互干擾,從而確保數(shù)據(jù)的一致性和可靠性。
1.1?原子類的作用
Java提供了一組原子類,位于java.util.concurrent.atomic
包中,用于在多線程環(huán)境下進(jìn)行原子操作。這些原子類利用底層的硬件支持或自旋鎖等機(jī)制來(lái)實(shí)現(xiàn)線程安全的操作,避免了顯式地使用synchronized
關(guān)鍵字等鎖機(jī)制,從而提高了并發(fā)性能。
原子類的作用主要有以下幾點(diǎn):
-
提供線程安全的操作: 原子類提供了一些常見(jiàn)的操作,如讀取、更新、比較交換等,這些操作在執(zhí)行時(shí)不會(huì)受到其他線程的干擾,從而確保數(shù)據(jù)的一致性。
-
避免競(jìng)態(tài)條件: 使用原子類可以有效地避免多線程環(huán)境下的競(jìng)態(tài)條件問(wèn)題,例如多個(gè)線程同時(shí)對(duì)同一個(gè)變量進(jìn)行操作,可能導(dǎo)致不可預(yù)測(cè)的結(jié)果。
-
提高性能: 原子類在實(shí)現(xiàn)上利用了一些底層的技術(shù),避免了傳統(tǒng)鎖機(jī)制的開銷,因此在某些情況下可以提供更好的性能。
1.2?原子類的常見(jiàn)操作
1. AtomicBoolean
AtomicBoolean
類提供了原子的布爾值操作,支持原子的設(shè)置和獲取操作。
AtomicBoolean atomicBoolean = new AtomicBoolean(true);boolean currentValue = atomicBoolean.get(); // 獲取當(dāng)前值
boolean updatedValue = atomicBoolean.compareAndSet(true, false); // 如果當(dāng)前值為true,則設(shè)置為false
?
2. AtomicInteger 和 AtomicLong
AtomicInteger
和AtomicLong
分別提供了原子的整數(shù)和長(zhǎng)整數(shù)操作,包括增加、減少、獲取等操作。
AtomicInteger atomicInt = new AtomicInteger(0);int currentValue = atomicInt.get(); // 獲取當(dāng)前值
int newValue = atomicInt.incrementAndGet(); // 增加1并返回新值
int updatedValue = atomicInt.addAndGet(5); // 增加5并返回新值
3. AtomicReference
AtomicReference
允許在原子級(jí)別上操作引用類型的數(shù)據(jù)。它提供了get
、set
和compareAndSet
等方法。
AtomicReference<String> atomicRef = new AtomicReference<>("initial value");String currentValue = atomicRef.get(); // 獲取當(dāng)前值
boolean updated = atomicRef.compareAndSet("initial value", "new value"); // 如果當(dāng)前值為"initial value",則設(shè)置為"new value"
?
4. AtomicStampedReference
AtomicStampedReference
是對(duì)AtomicReference
的擴(kuò)展,它還包含一個(gè)時(shí)間戳,用于解決ABA問(wèn)題(即一個(gè)值被修改為另一個(gè)值,然后又被修改回原來(lái)的值,但是在這之間可能發(fā)生了其他的變化)。
AtomicStampedReference<String> atomicStampedRef = new AtomicStampedReference<>("initial value", 0);int currentStamp = atomicStampedRef.getStamp(); // 獲取當(dāng)前時(shí)間戳
String currentValue = atomicStampedRef.getReference(); // 獲取當(dāng)前值
boolean updated = atomicStampedRef.compareAndSet("initial value", "new value", 0, 1); // 如果當(dāng)前值為"initial value"且時(shí)間戳為0,則設(shè)置為"new value"和時(shí)間戳為1
5. AtomicArray
AtomicArray
類允許在原子級(jí)別上操作數(shù)組元素,提供了針對(duì)數(shù)組元素的原子更新操作。
AtomicIntegerArray atomicIntArray = new AtomicIntegerArray(5);int currentValue = atomicIntArray.get(2); // 獲取索引為2的元素值
atomicIntArray.set(3, 10); // 設(shè)置索引為3的元素值為10
int updatedValue = atomicIntArray.getAndAdd(1, 5); // 增加索引為1的元素值,并返回舊值
6. AtomicReferenceFieldUpdater
AtomicReferenceFieldUpdater
是Java中的一個(gè)工具類,用于進(jìn)行原子更新類的引用類型字段的操作。它允許您在不使用鎖的情況下對(duì)指定的引用字段進(jìn)行原子操作,類似于AtomicFieldUpdater
,但專門用于引用類型的字段。AtomicReferenceFieldUpdater
主要用于確保在多線程環(huán)境下對(duì)引用字段的操作是線程安全的,并且可以提供更好的性能。
AtomicReferenceFieldUpdater
適用于以下場(chǎng)景:
-
當(dāng)您需要在不使用鎖的情況下對(duì)特定類的引用字段進(jìn)行原子更新時(shí)。
-
當(dāng)引用字段的訪問(wèn)修飾符是
volatile
,以確保多線程之間的可見(jiàn)性。 -
當(dāng)您希望在多個(gè)實(shí)例之間共享原子更新引用字段的功能,而不是整個(gè)對(duì)象。
要使用AtomicReferenceFieldUpdater
,首先需要?jiǎng)?chuàng)建一個(gè)AtomicReferenceFieldUpdater
的實(shí)例。這可以通過(guò)調(diào)用AtomicReferenceFieldUpdater.newUpdater(Class<T> tclass, Class<V> vclass, String fieldName)
方法來(lái)實(shí)現(xiàn),其中:
tclass
是包含字段的類的Class
對(duì)象。vclass
是字段的引用類型的Class
對(duì)象。fieldName
是要進(jìn)行原子操作的引用字段的名稱。
以下是一個(gè)示例代碼片段,演示如何創(chuàng)建和使用AtomicReferenceFieldUpdater
實(shí)例:
public class AtomicReferenceFieldUpdaterExample {public static class Student {public volatile String name;}public static void main(String[] args) {Student student = new Student();AtomicReferenceFieldUpdater<Student, String> updater =AtomicReferenceFieldUpdater.newUpdater(Student.class, String.class, "name");updater.set(student, "Alice"); // 原子地設(shè)置name字段為"Alice"String updatedName = updater.get(student); // 原子地獲取name字段的值System.out.println("Updated Name: " + updatedName);}
}
AtomicReferenceFieldUpdater
提供了一系列的原子操作方法,用于對(duì)指定引用字段進(jìn)行原子更新。這些方法包括:
-
boolean compareAndSet(T obj, V expect, V update)
:如果當(dāng)前值等于expect
,則將字段更新為update
,返回是否更新成功。 -
V getAndSet(T obj, V newValue)
:將字段更新為newValue
,并返回之前的值。 -
V getAndUpdate(T obj, UnaryOperator<V> updateFunction)
:使用給定的更新函數(shù)更新字段,并返回更新前的值。 -
V updateAndGet(T obj, UnaryOperator<V> updateFunction)
:使用給定的更新函數(shù)更新字段,并返回更新后的值。 -
V getAndAccumulate(T obj, V x, BinaryOperator<V> accumulatorFunction)
:使用給定的累加函數(shù)將字段與x
進(jìn)行累加操作,并返回更新前的值。 -
V accumulateAndGet(T obj, V x, BinaryOperator<V> accumulatorFunction)
:使用給定的累加函數(shù)將字段與x
進(jìn)行累加操作,并返回更新后的值。
7.?LongAdder
LongAdder
是Java并發(fā)包中提供的一種用于高并發(fā)場(chǎng)景下對(duì)long類型進(jìn)行累加操作的工具類。與傳統(tǒng)的AtomicLong
相比,LongAdder
在高并發(fā)情況下通常能夠提供更好的性能,因?yàn)樗捎昧艘环N分段的方式來(lái)減少競(jìng)爭(zhēng)。LongAdder
的引入主要是為了應(yīng)對(duì)高并發(fā)累加操作的性能瓶頸,特別是在多核處理器上。
LongAdder
在高并發(fā)場(chǎng)景下的主要優(yōu)勢(shì)在于分段累加,以及對(duì)熱點(diǎn)數(shù)據(jù)的分離處理。傳統(tǒng)的AtomicLong
在高并發(fā)情況下可能會(huì)因?yàn)槎嗑€程之間的競(jìng)爭(zhēng)而導(dǎo)致性能下降,而LongAdder
通過(guò)將累加操作分成多個(gè)段,每個(gè)段維護(hù)一個(gè)計(jì)數(shù)器,從而減少了競(jìng)爭(zhēng)。
另外,LongAdder
還引入了一種稱為“分離器”(Cell)的機(jī)制。分離器是計(jì)數(shù)器的基本單元,每個(gè)線程在累加時(shí)會(huì)選擇一個(gè)分離器進(jìn)行操作,這避免了多線程頻繁地競(jìng)爭(zhēng)同一個(gè)計(jì)數(shù)器,從而減少了競(jìng)爭(zhēng)帶來(lái)的開銷。
要使用LongAdder
,只需要簡(jiǎn)單地創(chuàng)建一個(gè)LongAdder
的實(shí)例即可:
LongAdder longAdder = new LongAdder();
?
LongAdder
提供了一些常用的方法來(lái)進(jìn)行累加操作:
-
void add(long x)
:將指定的值添加到計(jì)數(shù)器中。 -
void increment()
:將計(jì)數(shù)器增加1。 -
void decrement()
:將計(jì)數(shù)器減少1。 -
long sum()
:返回當(dāng)前計(jì)數(shù)器的總和。 -
void reset()
:將計(jì)數(shù)器重置為0。 -
void addThenReset(long x)
:將指定的值添加到計(jì)數(shù)器中,然后將計(jì)數(shù)器重置為0。
原子類的使用注意事項(xiàng)
-
性能考慮: 雖然原子類可以提供一定程度的性能優(yōu)勢(shì),但并不是適用于所有情況。在高并發(fā)場(chǎng)景下,考慮使用原子類;而在低并發(fā)、性能要求不高的情況下,可能傳統(tǒng)的同步機(jī)制更加合適。
-
CAS操作的限制: 原子類的底層實(shí)現(xiàn)主要依賴于CAS(Compare-And-Swap)操作,這是一種樂(lè)觀鎖機(jī)制。然而,CAS操作可能會(huì)在競(jìng)爭(zhēng)激烈的情況下導(dǎo)致自旋等待,影響性能。
-
ABA問(wèn)題: 原子類的CAS操作可能存在ABA問(wèn)題,即一個(gè)值從A變?yōu)锽,然后又從B變?yōu)锳,這時(shí)CAS操作可能會(huì)錯(cuò)誤地認(rèn)為值沒(méi)有發(fā)生變化??梢允褂?code>AtomicStampedReference來(lái)解決此問(wèn)題。
-
復(fù)合操作的原子性: 原子類的單個(gè)操作是原子的,但多個(gè)操作的組合并不一定是原子的。例如,
AtomicInteger
的incrementAndGet
操作是原子的,但在使用時(shí)仍然需要考慮復(fù)合操作的原子性。 -
適用范圍: 原子類適用于簡(jiǎn)單的原子操作,但并不適用于復(fù)雜的業(yè)務(wù)邏輯。對(duì)于復(fù)雜的操作,可能需要使用鎖等更高級(jí)的同步機(jī)制來(lái)確保線程安全。