JDK中的原子類

在java.util.concurrent.atomic包下面,有許多的原子類,這裏面的操做類型大多數與JAVA中基本類型的包裝類對應。目的是爲了防止高併發的狀況下,各個線程操做產生錯誤數據。這裏就經過AtomicInteger這個類進行爲你們簡單講解下。java

屬性介紹

經過源碼咱們發現。AtomicInteger中只有三個屬性,一個unsafe對象屬性,一個valueOffset屬性以及一個被volatile修飾的value屬性。多線程

1.unsafe屬性能夠看到是由Unsafe類調用其靜態方法生成。併發

public static Unsafe getUnsafe() {
		Class var0 = Reflection.getCallerClass();
		if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
			throw new SecurityException("Unsafe");
		} else {
			return theUnsafe;
		}
	}
複製代碼

Unsafe類提供了硬件級別的原子操做。裏面有許多的本地方法。JDK中的一些無鎖併發操做類都是基於它,裏面最主要的就是CAS相關操做。這塊我就不詳細說明了(有興趣的小夥伴能夠去了解下)。app

2.valueOffset屬性是當前類中值value對應的內存起始地址。經過當前類中的靜態代碼塊能夠看出,他的賦值狀況:函數

static {
        try {
            valueOffset = unsafe.objectFieldOffset
                (AtomicInteger.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }
複製代碼

他是經過unsafe獲取到當前類中的屬性的起始地址。來進行賦值。點擊到下面能夠看到調用的objectFieldOffset的native方法進行調用獲取。高併發

3.value屬性就是當前類中的值,這裏也就是咱們所須要的值。這裏能夠從外部傳遞過來。性能

public AtomicInteger(int initialValue) {
        value = initialValue;
    }
複製代碼

主要方法介紹

由當前的類型,咱們就能瞭解到這是一個原子類相關操做,即每個操做不須要考慮多線程併發的問題。裏面的方法以下:this

剛開始的構造函數以及get和set方法在這裏就不作說明了。atom

1.lazySet(int)這個方法字面上說是懶設值,看到對應方法上面的註解說。這個會最終設值(仍是有點懵。。)。因而點擊進去查看對應調用的方法:spa

public native void putOrderedInt(Object var1, long var2, int var4);
複製代碼

看到裏面調用的是unsafe的方法,putOrderedInt方法是putIntVolatile方法的延遲實現,不保證值的改變被其餘線程當即看到。同時,unsafe裏面還有對應的putVolatile方法,改方法能將改動的值當即刷新到內存中。以及存在普通的putInt方法,該方法不能保證當即刷新到內存中。

2.getAndSet(int newValue)方法是爲了設置值,裏面就用到了value的內存地址進行設值。

public final int getAndSet(int newValue) {
        return unsafe.getAndSetInt(this, valueOffset, newValue);
    }
複製代碼

3.compareAndSet(int expect, int update)這個方法就是基於CAS實現的更新數值。 經過無無鎖將多線程設置值的問題解決。若是設置成功返回true,反之沒設置成功。同時這裏也爲其餘操做提供了一個準確的保證。

public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }
複製代碼

4.weakCompareAndSet(int expect, int update)方法是針對於當前的數值交換狀況。將這個成員變量更新爲給定的更新後的值(update)若是當前值等於指望值(expect)時。

public final boolean weakCompareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }
複製代碼

相信一些小夥伴對此方法有點疑惑,由於若是是基於CAS交換的話,不必增長一個weak在方法名上,(同時讓咱們想起來JAVA中的四種引用類型。。),這裏官方就給出瞭解釋:

weakCompareAndSet底層不會建立任何happen-before的保證,也就是不會對volatile字段操做的先後加入內存屏障。由於就沒法保證多線程操做下對除了weakCompareAndSet操做的目標變量( 該目標變量必定是一個volatile變量 )之其餘的變量讀取和寫入數據的正確性。

5.getAndUpdate(IntUnaryOperator updateFunction)這個方法先很少說,直接上代碼:

public final int getAndUpdate(IntUnaryOperator updateFunction) {
        int prev, next;
        do {
            prev = get();
            next = updateFunction.applyAsInt(prev);
        } while (!compareAndSet(prev, next));
        return prev;
    }
複製代碼

這裏面是使用了循環進行更新值,利用的是以前的CAS操做判斷以前的值與以後的值是不是一致的關係。而後進行更新操做。這裏還使用了功能型接口IntUnaryOperator

整體來講:AtomicXXX相關的類的操做都是大體相同的,都是使用的是無鎖的CAS操做,對於性能方面可以有所提升,也不須要考慮線程阻塞的狀況發生。對於多線程操做的狀況下仍是很好的一個選擇。

相關文章
相關標籤/搜索