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