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