Java8并發(fā)教程-Atomic variables and ConcurrencyMap

這是本教程的最后一篇.我們還是用到了上一篇中提到的那個工具類和其中的兩個方法.請看上篇文章,來獲取此代碼.

AutomicInteger

** java.concurrent.atomic**包中,提供了大量的有用的類,來執(zhí)行原子性的操作.原子性的意思是,所有的操作要不就都執(zhí)行成功,要不就都不執(zhí)行成功.

這些原子性的類內(nèi)部,都使用了著名的** CAS指令.現(xiàn)代處理器都支持這條指令.相對于使用鎖的 synchronized**關(guān)鍵字來說,這條指令操作起來更快.所以,如果我們只想并發(fā)的對一個共享變量進行操作,那使用這些原子性的類,更為方便和快捷.

我們首先看一下** AutomicInteger**這個類如何使用:

通過使用** AutomicInteger類型,而不是 Integer類型,我們能夠以線程安全的方式,來并發(fā)的修改一個數(shù)值.而不需要跟以前一樣,使用 synchronized關(guān)鍵字或者顯式鎖. AutomicInteger類型提供的 incrementAndGet()**方法,是線程安全的,所以我們可以放心的在多個線程中使用這個方法,而不需要擔(dān)心那些預(yù)料之外的事情發(fā)生.

** AutomicInteger類型還提供了很多其他的原子性的方法.其中updateAndGet()**方法允許我們傳入一個lambda表達(dá)式,來對此數(shù)值就行操作.

** accumulateAndGet()方法,接受一種 IntBinaryOperator**類型的lambda表達(dá)式.在下面這個例子中,我們使用這個方法,來并發(fā)的計算0到1000的和.

** java.concurrent.atomic包中,還提供了很多其他的原子類.如 AutomicBoolean, AutomicLong, AutomicReference**等.

LongAddr

** LongAddr AtomicLong**相似,用于連續(xù)的為數(shù)值增加一個值.

** LongAddr還提供了其他的原子性的,線程安全的函數(shù),比如 add(),和 increment().但是,這些方法并不只是單純的計算一個結(jié)果,它還在內(nèi)部維護了很多變量,用于減少線程之間的沖突.我們可以通過 sum()方法和 sumThenRest()**方法,來獲取計算的結(jié)果.

這個類,在執(zhí)行寫操作的線程多于執(zhí)行讀操作的線程這種情景中,比較常用.通常用在那些需要獲取統(tǒng)計數(shù)據(jù)的情況中.比如,你想要計算服務(wù)器接受的請求數(shù).** LongAddr**的缺點是,由于要在內(nèi)存中維護大量的變量,所以它比較耗內(nèi)存.

LongAccumulator

** LongAccumulator LongAddr相似,但是更加常用.它執(zhí)行的不是簡單的操作,它接受的是 LongBinaryOperator**類型的lambda表達(dá)式.如下例所示:

我們通過函數(shù)** 2 * x + y和初始值1,創(chuàng)建了一個 LongAccumulator.每次調(diào)用 accumulate(i)**函數(shù),當(dāng)前值會作為lambda表達(dá)式的x值, i會作為lambda表達(dá)式的y值,傳遞到lambda表達(dá)式中.

** LongAccumulator就像 LongAddr**一樣,內(nèi)部也維護了大量的變量,來減少線程之間的沖突.

ConcurrentMap

** ConcurrentMap接口,擴充了 Map**接口,成為了并發(fā)編程中,最有用的一個接口.

我們想創(chuàng)建一個包含四對數(shù)據(jù)的** CouncurrentMap**.在后面我們將用它來實驗?zāi)切┖瘮?shù).

** forEach()方法接受一個類型為 BiConsumer的lambda表達(dá)式作為參數(shù),其中此lambda表達(dá)式的參數(shù)為map中的鍵值對.我們可以用 forEach()**這個方法來在當(dāng)前線程內(nèi),串行的迭代這個map.

** putIfAbsent()方法,會在給定的key沒有value時,為其添加一個value.至少在 ConcurrentHashMap**中,其實現(xiàn)是線程安全的.

** getOrDefault()**方法,會嘗試獲取給定key的value,如果不存在,則返回我們指定的默認(rèn)值.

** replaceAll()**方法,用于替換此Map中,滿足條件的項的value.

** compute()**方法,允許我們對特定的項進行轉(zhuǎn)換.

除了** compute()方法,還有兩個變體, computeIfAbsent() computeIfPresent()**,分別在給定的key不存在時和存在時進行操作.

** merge()**方法,用于對給定key的value進行操作,生成一個新的值.

ConcurrentHashMap

上面介紹的函數(shù),都是** ConcurrentMap這個接口提供的.這些函數(shù)可以被任何實現(xiàn)了 ConcurrentMap的類使用.除此之外, ConcurrentHashMap**還提供了很多其他用于并發(fā)操作的函數(shù).

就像parallel streams一樣,這些函數(shù)內(nèi)部都使用** ForkJoinPool,在Java8中,我們可以通過 ForkJoinPool.commonPool()函數(shù)來獲得一個 ForkJoinPool**.這個線程池,默認(rèn)可以使用的線程數(shù),取決于你的機器上的CPU上,有幾個核心.在我的四核的機器上,其為3.

我們可以通過設(shè)置JVM的參數(shù),來修改這個數(shù)值.

我們還是使用上面的那個包含四條數(shù)據(jù)的map.但是這里我們不使用** ConcurrentMap這個接口了,而是使用 ConcurrentHashMap這個具體實現(xiàn)類,來使用 ConcurrentHashMap**中特有的函數(shù).

Java8中,提供了三種并行操作的函數(shù):** forEach(), ** search()和** reduce()**.這些函數(shù)的第一個參數(shù),都是如果要啟動并發(fā)執(zhí)行的話,Collection的最小閾值.比如,如果我們設(shè)置了這個閾值為500,而map的大小為499,那就會在一個線程中,串行的執(zhí)行.而如果map的大小大于500,就會開啟多個線程,并行的執(zhí)行.在后面的例子中,我們將這個閾值設(shè)置為1,這就意味著,總是并行的執(zhí)行操作.

ForEach

** forEach()方法,用于并行的執(zhí)行迭代map中的key/value對的操作.因為在我的機器上, ForkJoinPool**的最大尺寸為3,所以在下面的例子中,你會看到,最多啟動了三個線程.

Search

** search()**函數(shù)用于并行的查找map中給定的key的值,如果找到,就返回其value,如果找不到,就返回null.如果會找到多個,則其返回值不確定.也要注意,ConcurrentHashMap中的元素是無序的.

還有一個只用于搜索map的value的方法,如下圖所示:

Reduce

** reduce()函數(shù),接受兩個類型為 BigFunction的lambda表達(dá)式.第一個lambda表達(dá)式,會將map中的每一個key/value對轉(zhuǎn)換成一個值,然后第二個lambda表達(dá)式,會將這些轉(zhuǎn)換后的值,拼接成一個單一的結(jié)果.它會忽略 null**.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末贬媒,一起剝皮案震驚了整個濱河市垄惧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌欢唾,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件狼忱,死亡現(xiàn)場離奇詭異种呐,居然都是意外死亡,警方通過查閱死者的電腦和手機穴墅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進店門惶室,熙熙樓的掌柜王于貴愁眉苦臉地迎上來温自,“玉大人,你說我怎么就攤上這事皇钞〉棵冢” “怎么了?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵夹界,是天一觀的道長馆里。 經(jīng)常有香客問我,道長可柿,這世上最難降的妖魔是什么鸠踪? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮复斥,結(jié)果婚禮上营密,老公的妹妹穿的比我還像新娘。我一直安慰自己目锭,他們只是感情好评汰,可當(dāng)我...
    茶點故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布纷捞。 她就那樣靜靜地躺著,像睡著了一般被去。 火紅的嫁衣襯著肌膚如雪主儡。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天惨缆,我揣著相機與錄音糜值,去河邊找鬼。 笑死坯墨,一個胖子當(dāng)著我的面吹牛臀玄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播畅蹂,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼健无,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了液斜?” 一聲冷哼從身側(cè)響起累贤,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎少漆,沒想到半個月后臼膏,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡示损,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年渗磅,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片检访。...
    茶點故事閱讀 40,427評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡始鱼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出脆贵,到底是詐尸還是另有隱情医清,我是刑警寧澤,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布卖氨,位于F島的核電站会烙,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏筒捺。R本人自食惡果不足惜柏腻,卻給世界環(huán)境...
    茶點故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望系吭。 院中可真熱鬧五嫂,春花似錦、人聲如沸村斟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至孩灯,卻和暖如春闺金,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背峰档。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工败匹, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人讥巡。 一個月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓掀亩,卻偏偏與公主長得像,于是被迫代替她去往敵國和親欢顷。 傳聞我的和親對象是個殘疾皇子槽棍,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,440評論 2 359

推薦閱讀更多精彩內(nèi)容

  • //Clojure入門教程: Clojure – Functional Programming for the J...
    葡萄喃喃囈語閱讀 3,680評論 0 7
  • 從三月份找實習(xí)到現(xiàn)在,面了一些公司抬驴,掛了不少炼七,但最終還是拿到小米、百度布持、阿里豌拙、京東、新浪题暖、CVTE按傅、樂視家的研發(fā)崗...
    時芥藍(lán)閱讀 42,272評論 11 349
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)胧卤,斷路器唯绍,智...
    卡卡羅2017閱讀 134,693評論 18 139
  • Java8張圖 11、字符串不變性 12灌侣、equals()方法推捐、hashCode()方法的區(qū)別 13、...
    Miley_MOJIE閱讀 3,707評論 0 11
  • 每假必住的意思就是每到放大假都要去住一下(^_^) 非度假村侧啼,非五星級酒店,而是一個舒適隨意適合深度休閑的小窩堪簿! ...
    索妮婭宋閱讀 462評論 0 2