摘要:注意原子數(shù)組并不是說可以讓線程以原子方式一次性地操作數(shù)組中所有元素的數(shù)組。類的方法返回指定類型數(shù)組的元素所占用的字節(jié)數(shù)。,是將轉(zhuǎn)換為進(jìn)制,然后從左往右數(shù)連續(xù)的個(gè)數(shù)。
本文首發(fā)于一世流云的專欄:https://segmentfault.com/blog...一、Atomic數(shù)組簡介
Atomic數(shù)組,顧名思義,就是能以原子的方式,操作數(shù)組中的元素。
JDK提供了三種類型的原子數(shù)組:AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray。
這三種類型大同小異,AtomicIntegerArray對(duì)應(yīng)AtomicInteger,AtomicLongArray對(duì)應(yīng)AtomicLong,AtomicReferenceArray對(duì)應(yīng)AtomicReference。
其實(shí)閱讀源碼也可以發(fā)現(xiàn),這些數(shù)組原子類與對(duì)應(yīng)的普通原子類相比,只是多了通過索引找到內(nèi)存中元素地址的操作而已。
注意:原子數(shù)組并不是說可以讓線程以原子方式一次性地操作數(shù)組中所有元素的數(shù)組。
而是指對(duì)于數(shù)組中的每個(gè)元素,可以以原子方式進(jìn)行操作。
說得簡單點(diǎn),原子數(shù)組類型其實(shí)可以看成原子類型組成的數(shù)組。
比如:
AtomicIntegerArray array = new AtomicIntegerArray(10); array.getAndIncrement(0); // 將第0個(gè)元素原子地增加1
等同于
AtomicInteger[] array = new AtomicInteger[10]; array[0].getAndIncrement(); // 將第0個(gè)元素原子地增加1二、AtomicIntegerArray原理
本節(jié)將以AtomicIntegerArray為例,介紹下原子數(shù)組的原理,AtomicLongArray和AtomicReferenceArray的使用和源碼與AtomicIntegerArray大同小異,讀者可以自己查看Oracle官方文檔和源碼。
AtomicIntegerArray其實(shí)和其它原子類區(qū)別并不大,只不過構(gòu)造的時(shí)候傳入的是一個(gè)int[]數(shù)組,然后底層通過Unsafe類操作數(shù)組:
可以看到,AtomicIntegerArray提供了兩種構(gòu)造器,本質(zhì)都是內(nèi)部利用array變量保存一個(gè)int[]數(shù)組引用。
另外,AtomicIntegerArray利用Unsafe類直接操作int[]對(duì)象的內(nèi)存地址,以達(dá)到操作數(shù)組元素的目的,幾個(gè)關(guān)鍵的變量解釋如下:
int base = unsafe.arrayBaseOffset(int[].class);
Unsafe類的arraBaseOffset方法:返回指定類型數(shù)組的第一個(gè)元素地址相對(duì)于數(shù)組起始地址的偏移值。
int scale = unsafe.arrayIndexScale(int[].class);
Unsafe類的arrayIndexScale方法:返回指定類型數(shù)組的元素所占用的字節(jié)數(shù)。比如int[]數(shù)組中的每個(gè)int元素占用4個(gè)字節(jié),就返回4。
那么,通過base + i * sacle 其實(shí)就可以知道 索引i的元素在數(shù)組中的內(nèi)存起始地址。
但是,觀察AtomicIntegerArray的byteOffset方法,是通過i << shift + base 的公式計(jì)算元素的起始地址的:
$$ i << shift + base = i * 2^{shift} + base $$
這里,$$ 2^{shift} $$其實(shí)就等于scale。
shift = 31 - Integer.numberOfLeadingZeros(scale),Integer.numberOfLeadingZeros(scale)是將scale轉(zhuǎn)換為2進(jìn)制,然后從左往右數(shù)連續(xù)0的個(gè)數(shù)。
讀者可以自己計(jì)算下:
shift = 31 - Integer.numberOfLeadingZeros(4) = 31 - 29 =2
之所以要這么繞一圈,其實(shí)是處于性能的考慮,通過移位計(jì)算乘法的效率往往更高。
三、AtomicIntegerArray接口聲明文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/76577.html
摘要:整個(gè)包,按照功能可以大致劃分如下鎖框架原子類框架同步器框架集合框架執(zhí)行器框架本系列將按上述順序分析,分析所基于的源碼為。后,根據(jù)一系列常見的多線程設(shè)計(jì)模式,設(shè)計(jì)了并發(fā)包,其中包下提供了一系列基礎(chǔ)的鎖工具,用以對(duì)等進(jìn)行補(bǔ)充增強(qiáng)。 showImg(https://segmentfault.com/img/remote/1460000016012623); 本文首發(fā)于一世流云專欄:https...
摘要:在并發(fā)量較低的環(huán)境下,線程沖突的概率比較小,自旋的次數(shù)不會(huì)很多。比如有三個(gè),每個(gè)線程對(duì)增加。的核心方法還是通過例子來看假設(shè)現(xiàn)在有一個(gè)對(duì)象,四個(gè)線程同時(shí)對(duì)進(jìn)行累加操作。 showImg(https://segmentfault.com/img/remote/1460000016012084); 本文首發(fā)于一世流云的專欄:https://segmentfault.com/blog... ...
摘要:本身不直接支持指針的操作,所以這也是該類命名為的原因之一。中的許多方法,內(nèi)部其實(shí)都是類在操作。 showImg(https://segmentfault.com/img/remote/1460000016012251); 本文首發(fā)于一世流云的專欄:https://segmentfault.com/blog... 一、Unsafe簡介 在正式的開講 juc-atomic框架系列之前,有...
摘要:所謂,就是可以以一種線程安全的方式操作非線程安全對(duì)象的某些字段。我們來對(duì)上述代碼進(jìn)行改造賬戶類改造引入通過操作字段調(diào)用方,并未做任何改變上述代碼,無論執(zhí)行多少次,最終結(jié)果都是,因?yàn)檫@回是線程安全的。這也是整個(gè)包的設(shè)計(jì)理念之一。 showImg(https://segmentfault.com/img/remote/1460000016012109); 本文首發(fā)于一世流云的專欄:http...
摘要:顧名思義,是類型的線程安全原子類,可以在應(yīng)用程序中以原子的方式更新值。創(chuàng)建對(duì)象先來看下對(duì)象的創(chuàng)建。也就是說當(dāng)一個(gè)線程修改一個(gè)共享變量時(shí),其它線程能立即讀到這個(gè)修改的值。 showImg(https://segmentfault.com/img/remote/1460000016012210); 本文首發(fā)于一世流云的專欄:https://segmentfault.com/blog... ...
閱讀 3729·2021-11-24 09:39
閱讀 2610·2019-08-30 15:54
閱讀 1149·2019-08-30 13:01
閱讀 3429·2019-08-28 18:30
閱讀 1623·2019-08-26 17:44
閱讀 3591·2019-08-26 11:31
閱讀 2413·2019-08-26 10:40
閱讀 1239·2019-08-26 10:27