摘要:否則它就會(huì)用新的值替代當(dāng)前值。在這種情況下,鎖可能會(huì)優(yōu)于原子變量,但在實(shí)際的爭(zhēng)用級(jí)別中,原子變量的性能優(yōu)于鎖。在中引入了另外一個(gè)構(gòu)件。
題目要求
在我們深入了解CAS(Compare And Swap)策略以及它是如何在AtomicInteger這樣的原子構(gòu)造器中使用的,首先來看一下這段代碼:
public class MyApp { private volatile int count = 0; public void upateVisitors() { ++count; //increment the visitors count } }
這里的代碼記錄的訪問應(yīng)用的訪客的數(shù)量。這段代碼有問題么?如果多個(gè)線程試圖更新這個(gè)數(shù)值會(huì)發(fā)生什么?事實(shí)上,這里的問題在于單單將count標(biāo)記為volatile并不能保證原子性,++count也不是一個(gè)原子操作。想要了解更多請(qǐng)查看這里。
那么如果我們將方法標(biāo)記為synchronized可以解決這個(gè)問題嗎?
public class MyApp { private int count = 0; public synchronized void upateVisitors() { ++count; //increment the visitors count } }
這段代碼可以保證原子性嗎?可以。
這段代碼可以保證可見性???可以。
那這里還有什么問題?
它使用了鎖從而引入了大量的延時(shí)和。詳情查看這里。這種方式開銷太大。
為了解決這個(gè)問題引入了原子構(gòu)造器。如果我們使用AtomicInteger來記錄訪問量,也可以達(dá)到目的。
public class MyApp { private AtomicInteger count = new AtomicInteger(0); public void upateVisitors() { count.incrementAndGet(); //increment the visitors count } }
支持原子操作的類如AtomicInteger,使用CAS來實(shí)現(xiàn)。CAS并沒有使用鎖,而是以一種很樂觀的方式來處理。它遵循以下幾步:
比較原始的值和我們已經(jīng)獲得的值
如果這兩個(gè)值不同,說明中間有線程改變了值。否則它就會(huì)用新的值替代當(dāng)前值。
看一下AtomicLong類中的代碼:
public final long incrementAndGet() { for (;;) { long current = get(); long next = current + 1; if (compareAndSet(current, next)) return next; } }
在JDK 8中上面的代碼被更改為一行代碼:
public final long incrementAndGet() { return unsafe.getAndAddLong(this, valueOffset, 1L) + 1L; }
這一行代碼有何優(yōu)點(diǎn)?
實(shí)際上,這一行是會(huì)由JIT翻譯為優(yōu)化的指令序列的JVM內(nèi)部函數(shù)。在x86架構(gòu)中它就是一條CPU指令LOCK XADD,會(huì)比CAS循環(huán)的性能好很多。
現(xiàn)在考慮一下當(dāng)我們有較高的爭(zhēng)用以及一些線程想要更??新相同的原子變量的可能性。在這種情況下,鎖可能會(huì)優(yōu)于原子變量,但在實(shí)際的爭(zhēng)用級(jí)別中,原子變量的性能優(yōu)于鎖。在Java 8 中引入了另外一個(gè)構(gòu)件LongAdder。
LongAdder并不完全是AtomicLong的替代品,我們需要考慮以下因素:
當(dāng)沒有爭(zhēng)用時(shí),AtomicLong性能更好
LongAdder將分配Cells(在抽象類Striped64中聲明的final類)以避免消耗內(nèi)存的爭(zhēng)用。所以如果我們有一個(gè)緊張的內(nèi)存預(yù)算,我們應(yīng)該更傾向于使用AtomicLong。
想要了解更多開發(fā)技術(shù),面試教程以及互聯(lián)網(wǎng)公司內(nèi)推,歡迎關(guān)注我的微信公眾號(hào)!將會(huì)不定期的發(fā)放福利哦~
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://hztianpu.com/yun/68794.html
摘要:簡(jiǎn)介從創(chuàng)建以來,就支持核心的并發(fā)概念如線程和鎖。這篇文章會(huì)幫助從事多線程編程的開發(fā)人員理解核心的并發(fā)概念以及如何使用它們。請(qǐng)求操作系統(tǒng)互斥,并讓操作系統(tǒng)調(diào)度程序處理線程停放和喚醒。 簡(jiǎn)介 從創(chuàng)建以來,JAVA就支持核心的并發(fā)概念如線程和鎖。這篇文章會(huì)幫助從事多線程編程的JAVA開發(fā)人員理解核心的并發(fā)概念以及如何使用它們。 (博主將在其中加上自己的理解以及自己想出的例子作為補(bǔ)充) 概念 ...
摘要:算法算法會(huì)先對(duì)一個(gè)內(nèi)存變量位置和一個(gè)給定的值進(jìn)行比較,如果相等,則用一個(gè)新值去修改這個(gè)內(nèi)存變量位置。因?yàn)槭欠枪芥i,所以一上來就嘗試搶占鎖給定舊值并希望用新值去更新內(nèi)存變量。 本文翻譯和原創(chuàng)各占一半,所以還是厚顏無恥歸類到原創(chuàng)好了...https://howtodoinjava.com/jav...java 5 其中一個(gè)令人振奮的改進(jìn)是新增了支持原子操作的類型,例如 AtomicInt...
摘要:有可能一個(gè)線程中的動(dòng)作相對(duì)于另一個(gè)線程出現(xiàn)亂序。當(dāng)實(shí)際輸出取決于線程交錯(cuò)的結(jié)果時(shí),這種情況被稱為競(jìng)爭(zhēng)條件。這里的問題在于代碼塊不是原子性的,而且實(shí)例的變化對(duì)別的線程不可見。這種不能同時(shí)在多個(gè)線程上執(zhí)行的部分被稱為關(guān)鍵部分。 為什么要額外寫一篇文章來研究volatile呢?是因?yàn)檫@可能是并發(fā)中最令人困惑以及最被誤解的結(jié)構(gòu)。我看過不少解釋volatile的博客,但是大多數(shù)要么不完整,要么難...
摘要:什么是仿射變換一組設(shè)備無關(guān)的坐標(biāo)被用來將所有的坐標(biāo)信息傳遞給對(duì)象。對(duì)象作為對(duì)象狀態(tài)的一部分。類代表一個(gè)的仿射變化,將一組的坐標(biāo)進(jìn)行線性映射到另一組保留了平行關(guān)系和豎直關(guān)系的坐標(biāo)中。 什么是仿射變換 一組設(shè)備無關(guān)的坐標(biāo)被用來將所有的坐標(biāo)信息傳遞給Graphics2D對(duì)象。AffineTransform對(duì)象作為Graphics2D對(duì)象狀態(tài)的一部分。該對(duì)象定義了如何將用戶空間的坐標(biāo)轉(zhuǎn)化為設(shè)備...
摘要:本文簡(jiǎn)介類概覽類構(gòu)造器總結(jié)類構(gòu)造方法類使用舉例類概覽是一個(gè)實(shí)現(xiàn)了接口,并且鍵為型的哈希表。中的條目不再被正常使用時(shí),會(huì)被自動(dòng)刪除。它的鍵值均支持。和絕大多數(shù)的集合類一樣,這個(gè)類不是同步的。 本文簡(jiǎn)介 WeakHashMap類概覽 WeakHashMap類構(gòu)造器總結(jié) WeakHashMap類構(gòu)造方法 WeakHasjMap類使用舉例 1. WeakHashMap類概覽 Wea...
閱讀 1079·2021-09-27 13:36
閱讀 1194·2021-09-08 09:35
閱讀 1228·2021-08-12 13:25
閱讀 1557·2019-08-29 16:52
閱讀 3075·2019-08-29 15:12
閱讀 2854·2019-08-29 14:17
閱讀 2759·2019-08-26 13:57
閱讀 1136·2019-08-26 13:51