摘要:前言為了研究對(duì)原子類(lèi)的實(shí)現(xiàn),從類(lèi)開(kāi)始,分析如果對(duì)原子操作的實(shí)現(xiàn)。保存著基礎(chǔ)數(shù)據(jù),使用修飾,可以保證該值對(duì)內(nèi)存可見(jiàn),也是原子類(lèi)實(shí)現(xiàn)的理論保障。使用自旋鎖來(lái)處理并發(fā)問(wèn)題。
前言
為了研究Java對(duì)原子類(lèi)的實(shí)現(xiàn),從AtomicInteger類(lèi)開(kāi)始,分析Java如果對(duì)原子操作的實(shí)現(xiàn)。
原子操作是指不會(huì)被線程調(diào)度機(jī)制打斷的操作;這種操作一旦開(kāi)始,就一直運(yùn)行到結(jié)束,中間不會(huì)有任何上下文的切換。
注:原子操作可以是一個(gè)步驟,也可以是多個(gè)操作步驟,但是其順序不可以被打亂,也不可以被切割只執(zhí)行其中的一部分。
首先從AtomicInteger類(lèi)的屬性聊起:
// setup to use Unsafe.compareAndSwapInt for updates private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final long valueOffset; private volatile int value;
該類(lèi)共有三個(gè)成員屬性。
unsafe:該類(lèi)是JDK提供的可以對(duì)內(nèi)存直接操作的工具類(lèi)。
valueOffset:該值保存著AtomicInteger基礎(chǔ)數(shù)據(jù)的內(nèi)存地址,方便unsafe直接對(duì)內(nèi)存的操作。
value:保存著AtomicInteger基礎(chǔ)數(shù)據(jù),使用volatile修飾,可以保證該值對(duì)內(nèi)存可見(jiàn),也是原子類(lèi)實(shí)現(xiàn)的理論保障。
再談靜態(tài)代碼塊(初始化)
try { valueOffset = unsafe.objectFieldOffset (AtomicInteger.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); } }
該過(guò)程實(shí)際上就是計(jì)算成員變量value的內(nèi)存偏移地址,計(jì)算后,可以更直接的對(duì)內(nèi)存進(jìn)行操作。
了解核心方法compareAndSet(int expect,int update):
public final boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); }
在該方法中調(diào)用了unsafe提供的服務(wù):
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
下面看看這個(gè)類(lèi)在JDK中是如何實(shí)現(xiàn)的:
jboolean sun::misc::Unsafe::compareAndSwapInt (jobject obj, jlong offset,jint expect, jint update) { jint *addr = (jint *)((char *)obj + offset); //1 return compareAndSwap (addr, expect, update); } static inline bool compareAndSwap (volatile jlong *addr, jlong old, jlong new_val) { jboolean result = false; spinlock lock; //2 if ((result = (*addr == old))) //3 *addr = new_val; //4 return result; //5 }
通過(guò)對(duì)象地址和value的偏移量地址,來(lái)計(jì)算value的內(nèi)存地址。
使用自旋鎖來(lái)處理并發(fā)問(wèn)題。
比較內(nèi)存中的值與調(diào)用方法時(shí)調(diào)用方所期待的值。
如果3中的比較符合預(yù)期,則重置內(nèi)存中的值。
如果成功置換則返回true,否則返回false;
綜上所述:compareAndSet的實(shí)現(xiàn)依賴于兩個(gè)條件:
volatile原語(yǔ):保證在操作內(nèi)存的值時(shí),該值的狀態(tài)為最新的。(被volatile所修飾的變量在讀取值時(shí)都會(huì)從變量的地址中讀取,而不是從寄存器中讀取,保證數(shù)據(jù)對(duì)所有線程都是可見(jiàn)的)
Unsafe類(lèi):通過(guò)該類(lèi)提供的功能,可以直接對(duì)內(nèi)存進(jìn)行操作。
了解常見(jiàn)操作getAndIncrement():
return unsafe.getAndAddInt(this, valueOffset, 1); }
同樣使用unsafe提供的方法:
public final int getAndAddInt(Object var1, long var2, int var4) { int var5; do { var5 = this.getIntVolatile(var1, var2);//1 } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));//2 return var5; } //getIntVolatile方法native實(shí)現(xiàn) jint sun::misc::Unsafe::getIntVolatile (jobject obj, jlong offset) { volatile jint *addr = (jint *) ((char *) obj + offset); //3 jint result = *addr; //4 read_barrier (); //5 return result; //6 } inline static void read_barrier(){ __asm__ __volatile__("" : : : "memory"); }
通過(guò)volatile方法獲取當(dāng)前內(nèi)存中該對(duì)象的value值。
計(jì)算value的內(nèi)存地址。
將值賦值給中間變量result。
插入讀屏障,保證該屏障之前的讀操作后后續(xù)的操作可見(jiàn)。
返回當(dāng)前內(nèi)存值
通過(guò)compareAndSwapInt操作對(duì)value進(jìn)行+1操作,如果再執(zhí)行該操作過(guò)程中,內(nèi)存數(shù)據(jù)發(fā)生變更,則執(zhí)行失敗,但循環(huán)操作直至成功。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/70830.html
摘要:前言今天的筆記來(lái)了解一下原子操作以及中如何實(shí)現(xiàn)原子操作。概念原子本意是不能被進(jìn)一步分割的最小粒子,而原子操作意為不可被中斷的一個(gè)或一系列操作。處理器實(shí)現(xiàn)原子操作處理器會(huì)保證基本內(nèi)存操作的原子性。 showImg(https://segmentfault.com/img/bVVIRA?w=1242&h=536); 前言 今天的筆記來(lái)了解一下原子操作以及Java中如何實(shí)現(xiàn)原子操作。 概念 ...
摘要:并發(fā)教程原子變量和原文譯者飛龍協(xié)議歡迎閱讀我的多線程編程系列教程的第三部分。如果你能夠在多線程中同時(shí)且安全地執(zhí)行某個(gè)操作,而不需要關(guān)鍵字或上一章中的鎖,那么這個(gè)操作就是原子的。當(dāng)多線程的更新比讀取更頻繁時(shí),這個(gè)類(lèi)通常比原子數(shù)值類(lèi)性能更好。 Java 8 并發(fā)教程:原子變量和 ConcurrentMap 原文:Java 8 Concurrency Tutorial: Synchroni...
摘要:本文探討并發(fā)中的其它問(wèn)題線程安全可見(jiàn)性活躍性等等。當(dāng)閉鎖到達(dá)結(jié)束狀態(tài)時(shí),門(mén)打開(kāi)并允許所有線程通過(guò)。在從返回時(shí)被叫醒時(shí),線程被放入鎖池,與其他線程競(jìng)爭(zhēng)重新獲得鎖。 本文探討Java并發(fā)中的其它問(wèn)題:線程安全、可見(jiàn)性、活躍性等等。 在行文之前,我想先推薦以下兩份資料,質(zhì)量很高:極客學(xué)院-Java并發(fā)編程讀書(shū)筆記-《Java并發(fā)編程實(shí)戰(zhàn)》 線程安全 《Java并發(fā)編程實(shí)戰(zhàn)》中提到了太多的術(shù)語(yǔ)...
摘要:今天給大家總結(jié)一下,面試中出鏡率很高的幾個(gè)多線程面試題,希望對(duì)大家學(xué)習(xí)和面試都能有所幫助。指令重排在單線程環(huán)境下不會(huì)出先問(wèn)題,但是在多線程環(huán)境下會(huì)導(dǎo)致一個(gè)線程獲得還沒(méi)有初始化的實(shí)例。使用可以禁止的指令重排,保證在多線程環(huán)境下也能正常運(yùn)行。 下面最近發(fā)的一些并發(fā)編程的文章匯總,通過(guò)閱讀這些文章大家再看大廠面試中的并發(fā)編程問(wèn)題就沒(méi)有那么頭疼了。今天給大家總結(jié)一下,面試中出鏡率很高的幾個(gè)多線...
閱讀 4236·2023-04-25 16:32
閱讀 2296·2021-09-28 09:36
閱讀 2109·2021-09-06 15:02
閱讀 762·2021-09-02 15:21
閱讀 988·2019-08-30 15:56
閱讀 3588·2019-08-30 15:45
閱讀 1784·2019-08-30 13:09
閱讀 454·2019-08-29 16:05