本篇內(nèi)容介紹了“高級(jí)并發(fā)編程系列之什么是原子類”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
成都創(chuàng)新互聯(lián)公司堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時(shí)代的保靖網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!
相信作為資深程序員的你,對(duì)于AtomicInteger這樣的類,即以Atomic開(kāi)始的類一定不會(huì)感到陌生。我們?cè)诜春芏嗫蚣茉创a、或者第三方組件都會(huì)經(jīng)常看到它們,如影隨形。
那么問(wèn)題來(lái)了,像Atomicxxx這樣的類,到底是什么意思呢?從字面意思比較好理解,Atomic即原子性,那么Atomicxxx即原子類。講到這里,你一定還記得我們說(shuō)過(guò)線程安全的三個(gè)基本要素,我們一起來(lái)回顧一下:可見(jiàn)性、原子性、有序性。原子類的原子性,講的就是這個(gè)原子性,于是你可以先記住一個(gè)結(jié)論:原子類,它是線程安全的類。
到這里有朋友可能會(huì)提出質(zhì)疑:你說(shuō)線程安全,就線程安全嗎?我不服,你沒(méi)有講清楚。我不聽(tīng),我不聽(tīng)......好吧,看官們莫急,且聽(tīng)我一步一步分析,娓娓道來(lái),話說(shuō)......
#考考你: 1.你真的理解原子類的核心思想嗎 2.你在你的項(xiàng)目中,有直接用到過(guò)原子類嗎
案例描述:
定義一個(gè)普通的int型變量value,初始值為:0
開(kāi)啟兩個(gè)線程thread_1,thread_2并行執(zhí)行value++操作
每個(gè)線程執(zhí)行 5000次,預(yù)期執(zhí)行結(jié)果: 2 * 5000 = 10000次
通過(guò)觀察最終執(zhí)行結(jié)果,是否等于預(yù)期10000次
結(jié)果不相等,說(shuō)明線程不安全,原因是:value++操作不是一個(gè)原子性操作
package com.anan.edu.common.newthread.atomic; /** * 普通 int變量 ++ 操作,非原子性,線程不安全 * * @author ThinkPad * @version 1.0 * @date 2020/11/29 8:27 */ public class CommonIntDemo { /** * 普通成員變量 */ private int value = 0; public void addValue(){ value++; } public static void main(String[] args) throws InterruptedException { // 1.創(chuàng)建CommonIntDemo對(duì)象 CommonIntDemo demo = new CommonIntDemo(); // 2.創(chuàng)建2兩個(gè)線程,每個(gè)線程調(diào)用方法addValue 5000次 // 預(yù)期value值結(jié)果等于:2 * 5000 = 10000 int loopEnd = 5000; Thread thread_1 = new Thread(() -> { for(int i = 0; i < loopEnd; i++){ demo.addValue(); } }, "thread_1"); Thread thread_2 = new Thread(() -> { for(int i = 0; i < loopEnd; i++){ demo.addValue(); } }, "thread_2"); // 3.啟動(dòng)執(zhí)行線程 thread_1.start(); thread_2.start(); // 4.主線程等待子線程執(zhí)行完成,打印value值 thread_1.join(); thread_2.join(); System.out.println("int型成員變量value最終結(jié)果:" + demo.value); } }
執(zhí)行結(jié)果分析:
案例描述:
定義一個(gè)AtomicInteger變量value,初始值為:0
開(kāi)啟兩個(gè)線程thread_1,thread_2并行執(zhí)行value.incrementAndGet()操作
每個(gè)線程執(zhí)行 5000次,預(yù)期執(zhí)行結(jié)果: 2 * 5000 = 10000次
通過(guò)觀察最終執(zhí)行結(jié)果,是否等于預(yù)期10000次
結(jié)果相等,說(shuō)明線程安全,原因是:原子類同時(shí)滿足了可見(jiàn)性、與原子性
package com.anan.edu.common.newthread.atomic; import java.util.concurrent.atomic.AtomicInteger; /** * 原子類AtomicInteger,實(shí)現(xiàn)自增操作,線程安全 * * @author ThinkPad * @version 1.0 * @date 2020/11/29 8:27 */ public class AtomicIntegerDemo { /** * AtomicInteger成員變量 */ private AtomicInteger value = new AtomicInteger(0); public void addValue(){ value.incrementAndGet(); } public static void main(String[] args) throws InterruptedException { // 1.創(chuàng)建AtomicIntegerDemo對(duì)象 AtomicIntegerDemo demo = new AtomicIntegerDemo(); // 2.創(chuàng)建2兩個(gè)線程,每個(gè)線程調(diào)用方法addValue 5000次 // 預(yù)期value值結(jié)果等于:2 * 5000 = 10000 int loopEnd = 5000; Thread thread_1 = new Thread(() -> { for(int i = 0; i < loopEnd; i++){ demo.addValue(); } }, "thread_1"); Thread thread_2 = new Thread(() -> { for(int i = 0; i < loopEnd; i++){ demo.addValue(); } }, "thread_2"); // 3.啟動(dòng)執(zhí)行線程 thread_1.start(); thread_2.start(); // 4.主線程等待子線程執(zhí)行完成,打印value值 thread_1.join(); thread_2.join(); System.out.println("AtomicInteger型成員變量value最終結(jié)果:" + demo.value); } }
執(zhí)行結(jié)果分析:
通過(guò)比較普通類型int型變量自增操作,與原子型AtomicInteger型變量自增操作。我們看到應(yīng)用層代碼幾乎沒(méi)有差異,僅僅是通過(guò)AtomicInteger替換int實(shí)現(xiàn)自增操作,即保證了線程安全。那么AtomicInteger它是如何做到的呢?
要分析清楚AtomicInteger底層原理,還需要回到我們說(shuō)過(guò)的線程安全基本要素:可見(jiàn)性、原子性、有序性。就是說(shuō)不管通過(guò)什么手段,要實(shí)現(xiàn)線程安全,一定要滿足這三個(gè)基本要素,換句話說(shuō),滿足了三個(gè)基本要素,也即實(shí)現(xiàn)了線程安全。
那么我們就從這三個(gè)要素開(kāi)始分析。首先看最容易理解的有序性,你還記得什么是有序性嗎?它是說(shuō)線程內(nèi)有序,線程之間無(wú)序。有序性比較好理解,我們就不過(guò)多解釋了。
再來(lái)看可見(jiàn)性,同樣你還記得什么是可見(jiàn)性嗎?我們知道jmm內(nèi)存模型,每個(gè)線程都有自己的私人空間(工作內(nèi)存),所有線程共享公共空間(主內(nèi)存)。那么如果要保證某個(gè)變量在線程間的可見(jiàn)性,即當(dāng)線程A操作該變量后,需要同步將變量值從私人空間同步到公共空間:工作內(nèi)存--->主內(nèi)存;同理其它線程在操作變量前,需要從公共空間將變量值同步到私人空間:主內(nèi)存--->工作內(nèi)存。java編程語(yǔ)法上給我們提供了一個(gè)關(guān)鍵字:volatile。用于實(shí)現(xiàn)可見(jiàn)性。你可能還需要下面這個(gè)圖:
最后再來(lái)看原子性,原子性你應(yīng)該還記得,我們上一篇:高級(jí)并發(fā)編程系列十二(一文搞懂cas)剛剛分享過(guò)。cas本質(zhì)上是不到黃河心不死,什么意思呢?即是不釋放cpu,循環(huán)操作,直到操作成功為止。我們是這么解釋的,你也應(yīng)該還記得對(duì)吧。而且我們還說(shuō)過(guò)對(duì)于cas,它的操作原理是三個(gè)值:內(nèi)存值A(chǔ)、期望值B、更新值C。每次操作都會(huì)比較內(nèi)存值A(chǔ),是否等于期望值B、如果等于則將內(nèi)存值更新成值C,操作成功;如果內(nèi)存值A(chǔ),不等于期望值B,則操作失敗,進(jìn)行下一次循環(huán)操作。你可能還需要下面這個(gè)圖:
好了到這里,我們可以一起來(lái)看AtomicInteger的源碼了??纯词欠駶M足我們說(shuō)的可見(jiàn)性、原子性。進(jìn)一步分析清楚AtomicInteger類線程安全的實(shí)現(xiàn)原理。下面我們通過(guò)截圖+文字描述的方式,方便你理解。
先來(lái)看AtomicInteger類的聲明,這一塊對(duì)于不熟悉的朋友可能比較難看懂,我們先截圖看一下。
通過(guò)類聲明部分源碼,我們看到線程安全的可見(jiàn)性,通過(guò)volatile關(guān)鍵字修飾value成員變量,已經(jīng)有了保障。那么原子性,又是如何保障的呢?答案是通過(guò)Unsafe工具類,進(jìn)行cas操作來(lái)保障的??磮D:
相信通過(guò)上面的分析,你已經(jīng)理解了原子類線程安全的底層實(shí)現(xiàn)原理,如果你理解起來(lái)稍微還有點(diǎn)難度,我建議你多看兩遍。對(duì)于一個(gè)程序員來(lái)說(shuō),我們不應(yīng)該只會(huì)用用框架,底層思想和原理才是內(nèi)功。
那么關(guān)于原子類的底層分析,我們暫時(shí)放一放,下面我們一起來(lái)看一下juc包中提供的常見(jiàn)原子能力工具類。它們每一個(gè)的底層原理,都在上面分析過(guò)了,我就不再逐一分析了,只是簡(jiǎn)單的列舉出來(lái),如果你感興趣的話,可以找一兩個(gè)按照我上面的分析思路,自己分析一下,應(yīng)該會(huì)有意想不到的驚喜!
基本原子類,代表:AtomicInteger、AtomicLong
數(shù)組原子類,代表:AtomicIntegerArray、AtomicLongArray
引用原子類,代表:AtomicReference<V>。關(guān)于引用原子類,稍微加一句:它可以把一個(gè)普通對(duì)象,包裝成具有原子能力的對(duì)象
提供升級(jí)能力原子類,代表:AtomicIntegerFieldUpdater、AtomicLongFieldUpdater
累加器原子類,代表:LongAdder。關(guān)于累加器,稍微多加一句:它是jdk1.8開(kāi)始后新加入的小伙伴,性能比起AtomicLong來(lái)說(shuō)杠杠的。
“高級(jí)并發(fā)編程系列之什么是原子類”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
當(dāng)前文章:高級(jí)并發(fā)編程系列之什么是原子類
文章鏈接:http://aaarwkj.com/article38/iijjpp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供自適應(yīng)網(wǎng)站、網(wǎng)站制作、建站公司、、網(wǎng)站建設(shè)、網(wǎng)站收錄
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
移動(dòng)網(wǎng)站建設(shè)知識(shí)