摘要:前言線程中的包里面都是類都是針對多線程下的原子變量,有包括等等多種變量的原子化實現(xiàn)。這也會對理解現(xiàn)實場景中,多線程程序原子化使用某個資源也有更好的理解。
前言
Java線程中的java.util.concurrent.atomic包里面都是類都是針對多線程下的原子變量,有包括AtomicInteger, AtomicBoolean等等多種變量的原子化實現(xiàn)。
本次我們將會解讀AtomicInteger的源碼,對變量的原子化思路進(jìn)行一個理解。這也會對理解現(xiàn)實場景中,多線程程序原子化使用某個資源也有更好的理解。我們抽取幾個主要的方法進(jìn)行解讀。
畫個UMLAtomicInteger主要實現(xiàn)了Number接口,這個接口提供的方法都是將原子變量值轉(zhuǎn)換為其他類型值的接口。
而主要的原子化特性則是通過持有jdk.internal.misc.Unsafe對象實現(xiàn)Proxy模式進(jìn)行實現(xiàn)。
初始化兩個靜態(tài)變量十分清晰:
U
是調(diào)用了jdk.internal.misc.Unsafe對象,協(xié)助后面的原子性更新特性。
VALUE
則是使用了objectFieldOffset獲取了對象在JVM內(nèi)存中的地址。該方法的具體實現(xiàn)則是一個native方法,通過C或C++對JVM內(nèi)部進(jìn)行操作。暫時不作細(xì)究。
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe(); private static final long VALUE = U.objectFieldOffset(AtomicInteger.class, "value"); private volatile int value;
構(gòu)造函數(shù)
AtomicInteger(int)
將傳入int值,寫入為成員變量,令對象持有該值。
主要API及源碼解讀
int get()
比較直觀的實現(xiàn),直接返回被聲明為volatile的value。
void set(int)
比較直觀的實現(xiàn),將輸入值賦值到為volatile的value。
int getAndIncrement()
有效的邏輯,在調(diào)用Unsafe對象的下面兩個方法:
public final int getAndAddInt(Object o, long offset, int delta) { int v; do {// 循環(huán) // getIntVolatile是一個native方法: // 以內(nèi)存地址,及Object對象確定獲取內(nèi)存中的volatile值 v = getIntVolatile(o, offset); } while (!weakCompareAndSetInt(o, offset, v, v + delta)); //調(diào)用下方的weakCompareAndSetInt方法,直到更新成功則退出循環(huán) return v; } public final boolean weakCompareAndSetInt(Object o, long offset, int expected, int x) { // 調(diào)用native方法compareAndSetInt // 以對象類型o,內(nèi)存地址offset,期望值expected,輸入值x // 按照對象類型及內(nèi)存地址獲得期待值,對比后更新為輸入值。 return compareAndSetInt(o, offset, expected, x); }
int getAndDecrement()
類似于getAndIncreement,調(diào)用Unsafe,對內(nèi)存中數(shù)值進(jìn)行操作。小結(jié)及延伸思考
通過回顧針對AtomiInteger的幾個基本方法原子化操作的解讀,我們可以理解為原子操作的幾個要點:
采用volatile類型的特性,直接讀取內(nèi)存中的值,忽略掉VM中的值。
采用對比的方法,對比對象類型,內(nèi)存地址,原有值等維度,核對后進(jìn)行賦值。(具體要檢查native方法的代碼)
Atomic類忽略了值的次序性,盡可能以值的唯一性保證其原子性。
對于數(shù)據(jù)庫記錄的原子性的解決方案,也有類似的解決方案,多線程占用某個數(shù)據(jù)庫資源更新時,我們也可以先做讀取,核對值或版本號后再作更新。
對于數(shù)據(jù)庫相關(guān)的原子性保證更新,我們下一篇再聊聊。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/76804.html
摘要:的內(nèi)置鎖是一種互斥鎖,意味著最多只有一個線程能持有這種鎖。使用方式如下使用顯示鎖之前,解決多線程共享對象訪問的機(jī)制只有和。后面會陸續(xù)的補(bǔ)充并發(fā)編程系列的文章。 早期的計算機(jī)不包含操作系統(tǒng),它們從頭到尾執(zhí)行一個程序,這個程序可以訪問計算機(jī)中的所有資源。在這種情況下,每次都只能運行一個程序,對于昂貴的計算機(jī)資源來說是一種嚴(yán)重的浪費。 操作系統(tǒng)出現(xiàn)后,計算機(jī)可以運行多個程序,不同的程序在單獨...
摘要:多線程編程就像一個沼澤,中間遍布各種各樣的陷阱。但是在多線程編程或者說是并發(fā)編程中,有非常多的陷阱被埋在底層細(xì)節(jié)當(dāng)中。線程池類中用于控制線程池狀態(tài)和線程數(shù)的控制變量就是一個類型的字段。 多線程編程就像一個沼澤,中間遍布各種各樣的陷阱。大多數(shù)開發(fā)者絕大部分時間都是在做上層應(yīng)用的開發(fā),并不需要過多地涉入底層細(xì)節(jié)。但是在多線程編程或者說是并發(fā)編程中,有非常多的陷阱被埋在底層細(xì)節(jié)當(dāng)中。如果不知...
摘要:簡介從創(chuàng)建以來,就支持核心的并發(fā)概念如線程和鎖。這篇文章會幫助從事多線程編程的開發(fā)人員理解核心的并發(fā)概念以及如何使用它們。請求操作系統(tǒng)互斥,并讓操作系統(tǒng)調(diào)度程序處理線程停放和喚醒。 簡介 從創(chuàng)建以來,JAVA就支持核心的并發(fā)概念如線程和鎖。這篇文章會幫助從事多線程編程的JAVA開發(fā)人員理解核心的并發(fā)概念以及如何使用它們。 (博主將在其中加上自己的理解以及自己想出的例子作為補(bǔ)充) 概念 ...
摘要:所以接下來,我們需要簡單的介紹下多線程中的并發(fā)通信模型。比如中,以及各種鎖機(jī)制,均為了解決線程間公共狀態(tài)的串行訪問問題。 并發(fā)的學(xué)習(xí)門檻較高,相較單純的羅列并發(fā)編程 API 的枯燥被動學(xué)習(xí)方式,本系列文章試圖用一個簡單的栗子,一步步結(jié)合并發(fā)編程的相關(guān)知識分析舊有實現(xiàn)的不足,再實現(xiàn)邏輯進(jìn)行分析改進(jìn),試圖展示例子背后的并發(fā)工具與實現(xiàn)原理。 本文是本系列的第一篇文章,提出了一個簡單的業(yè)務(wù)場景...
摘要:在上一篇文章從到實現(xiàn)自己的阻塞隊列上中,我們已經(jīng)實現(xiàn)了一個可以使用的阻塞隊列版本。插入鎖隊列未滿的條件變量彈出鎖隊列非空的條件變量最后我們要對和方法中的調(diào)用做出一些調(diào)整。 在上一篇文章《從0到1實現(xiàn)自己的阻塞隊列(上)》中,我們已經(jīng)實現(xiàn)了一個可以使用的阻塞隊列版本。在這篇文章中,我們可以繼續(xù)我們的冒險之旅,將我們的阻塞隊列提升到接近JDK版本的水平上。 更進(jìn)一步優(yōu)化效率 我們一直使用的...
閱讀 3669·2021-11-15 11:37
閱讀 2993·2021-11-12 10:36
閱讀 4469·2021-09-22 15:51
閱讀 2395·2021-08-27 16:18
閱讀 902·2019-08-30 15:44
閱讀 2177·2019-08-30 10:58
閱讀 1794·2019-08-29 17:18
閱讀 3290·2019-08-28 18:25