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

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

atomic的实现原理

發(fā)布時(shí)間:2023/12/16 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 atomic的实现原理 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

? ?
? ? ?在多線(xiàn)程的場(chǎng)景中,我們需要保證數(shù)據(jù)安全,就會(huì)考慮同步的方案,通常會(huì)使用synchronized或者lock來(lái)處理,使用了synchronized意味著內(nèi)核態(tài)的一次切換。這是一個(gè)很重的操作。

? ? ?有沒(méi)有一種方式,可以比較便利的實(shí)現(xiàn)一些簡(jiǎn)單的數(shù)據(jù)同步,比如計(jì)數(shù)器等等。concurrent包下的atomic提供我們這么一種輕量級(jí)的數(shù)據(jù)同步的選擇。

class MyThread implements Runnable {static AtomicInteger ai=new AtomicInteger(0);public void run() {for (int m = 0; m < 1000000; m++) {ai.getAndIncrement();}} };public class TestAtomicInteger {public static void main(String[] args) throws InterruptedException {MyThread mt = new MyThread();Thread t1 = new Thread(mt);Thread t2 = new Thread(mt);t1.start();t2.start();Thread.sleep(500);System.out.println(MyThread.ai.get());} }

? ? ? 在以上代碼中,使用AtomicInteger聲明了一個(gè)全局變量,并且在多線(xiàn)程中進(jìn)行自增,代碼中并沒(méi)有進(jìn)行顯示的加鎖。以上代碼的輸出結(jié)果,永遠(yuǎn)都是2000000。如果將AtomicInteger換成Integer,打印結(jié)果基本都是小于2000000。
? ? ? 也就說(shuō)明AtomicInteger聲明的變量,在多線(xiàn)程場(chǎng)景中的自增操作是可以保證線(xiàn)程安全的。接下來(lái)我們分析下其原理。

原理

? ? ? 這里,我們來(lái)看看AtomicInteger是如何使用非阻塞算法來(lái)實(shí)現(xiàn)并發(fā)控制的。
? ? ? AtomicInteger的關(guān)鍵域只有一下3個(gè):

public class AtomicInteger extends Number implements java.io.Serializable {private static final long serialVersionUID = 6214790243416807050L;// setup to use Unsafe.compareAndSwapInt for updatesprivate static final Unsafe unsafe = Unsafe.getUnsafe();private static final long valueOffset;static {try {valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));} catch (Exception ex) { throw new Error(ex); }}private volatile int value;/*** Creates a new AtomicInteger with the given initial value.** @param initialValue the initial value*/public AtomicInteger(int initialValue) {value = initialValue;}/*** Creates a new AtomicInteger with initial value {@code 0}.*/public AtomicInteger() {}...... }

? ? ? 這里, unsafe是java提供的獲得對(duì)對(duì)象內(nèi)存地址訪(fǎng)問(wèn)的類(lèi),注釋已經(jīng)清楚的寫(xiě)出了,它的作用就是在更新操作時(shí)提供“比較并替換”的作用。實(shí)際上就是AtomicInteger中的一個(gè)工具。

? ? ? valueOffset是用來(lái)記錄value本身在內(nèi)存的編譯地址的,這個(gè)記錄,也主要是為了在更新操作在內(nèi)存中找到value的位置,方便比較。

? ? ?value是用來(lái)存儲(chǔ)整數(shù)的時(shí)間變量,這里被聲明為volatile。volatile只能保證這個(gè)變量的可見(jiàn)性。不能保證他的原子性。

? ? ?可以看看getAndIncrement這個(gè)類(lèi)似i++的函數(shù),可以發(fā)現(xiàn),是調(diào)用了UnSafe中的getAndAddInt。

/*** Atomically increments by one the current value.** @return the previous value*/public final int getAndIncrement() {return unsafe.getAndAddInt(this, valueOffset, 1);}/*** Atomically sets to the given value and returns the old value.** @param newValue the new value* @return the previous value*/public final int getAndSet(int newValue) {return unsafe.getAndSetInt(this, valueOffset, newValue);}public final int getAndSetInt(Object var1, long var2, int var4) {int var5;do {var5 = this.getIntVolatile(var1, var2);//使用unsafe的native方法,實(shí)現(xiàn)高效的硬件級(jí)別CAS} while(!this.compareAndSwapInt(var1, var2, var5, var4));return var5;}

? ? ? 如何保證原子性:自旋 + CAS(樂(lè)觀鎖)。在這個(gè)過(guò)程中,通過(guò)compareAndSwapInt比較更新value值,如果更新失敗,重新獲取舊值,然后更新。


優(yōu)缺點(diǎn)

? ? ? CAS相對(duì)于其他鎖,不會(huì)進(jìn)行內(nèi)核態(tài)操作,有著一些性能的提升。但同時(shí)引入自旋,當(dāng)鎖競(jìng)爭(zhēng)較大的時(shí)候,自旋次數(shù)會(huì)增多。cpu資源會(huì)消耗很高。

? ? ? 換句話(huà)說(shuō),CAS+自旋適合使用在低并發(fā)有同步數(shù)據(jù)的應(yīng)用場(chǎng)景。

?

Java 8做出的改進(jìn)和努力

? ? ? 在Java 8中引入了4個(gè)新的計(jì)數(shù)器類(lèi)型,LongAdder、LongAccumulator、DoubleAdder、DoubleAccumulator。他們都是繼承于Striped64。

? ? ?在LongAdder 與AtomicLong有什么區(qū)別?
Atomic*遇到的問(wèn)題是,只能運(yùn)用于低并發(fā)場(chǎng)景。因此LongAddr在這基礎(chǔ)上引入了分段鎖的概念。可以參考《JDK8系列之LongAdder解析》一起看看做了什么。

? ? ?大概就是當(dāng)競(jìng)爭(zhēng)不激烈的時(shí)候,所有線(xiàn)程都是通過(guò)CAS對(duì)同一個(gè)變量(Base)進(jìn)行修改,當(dāng)競(jìng)爭(zhēng)激烈的時(shí)候,會(huì)將根據(jù)當(dāng)前線(xiàn)程哈希到對(duì)于Cell上進(jìn)行修改(多段鎖)。

/*** Table of cells. When non-null, size is a power of 2.*/transient volatile Cell[] cells;/*** Base value, used mainly when there is no contention, but also as* a fallback during table initialization races. Updated via CAS.*/transient volatile long base; /*** Padded variant of AtomicLong supporting only raw accesses plus CAS.** JVM intrinsics note: It would be possible to use a release-only* form of CAS here, if it were provided.*/@sun.misc.Contended static final class Cell {volatile long value;Cell(long x) { value = x; }final boolean cas(long cmp, long val) {return UNSAFE.compareAndSwapLong(this, valueOffset, cmp, val);}// Unsafe mechanicsprivate static final sun.misc.Unsafe UNSAFE;private static final long valueOffset;static {try {UNSAFE = sun.misc.Unsafe.getUnsafe();Class<?> ak = Cell.class;valueOffset = UNSAFE.objectFieldOffset(ak.getDeclaredField("value"));} catch (Exception e) {throw new Error(e);}}}

? ? ?可以看到大概實(shí)現(xiàn)原理是:通過(guò)CAS樂(lè)觀鎖保證原子性,通過(guò)自旋保證當(dāng)次修改的最終修改成功,通過(guò)降低鎖粒度(多段鎖)增加并發(fā)性能。

?

?

Refrence:
https://mp.weixin.qq.com/s/aw6OXC9wkxH42rCywNd7yQ

?

?

總結(jié)

以上是生活随笔為你收集整理的atomic的实现原理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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