Java并發(fā)編程包中atomic的實(shí)現(xiàn)原理示例詳解

線程安全:

成都創(chuàng)新互聯(lián)公司是創(chuàng)新、創(chuàng)意、研發(fā)型一體的綜合型網(wǎng)站建設(shè)公司,自成立以來公司不斷探索創(chuàng)新,始終堅(jiān)持為客戶提供滿意周到的服務(wù),在本地打下了良好的口碑,在過去的十余年時(shí)間我們累計(jì)服務(wù)了上千家以及全國政企客戶,如航空箱等企業(yè)單位,完善的項(xiàng)目管理流程,嚴(yán)格把控項(xiàng)目進(jìn)度與質(zhì)量監(jiān)控加上過硬的技術(shù)實(shí)力獲得客戶的一致贊美。

當(dāng)多個(gè)線程訪問某個(gè)類時(shí),不管運(yùn)行時(shí)環(huán)境采用何種調(diào)度方式或者這些進(jìn)程將如何交替執(zhí)行,并且在主調(diào)代碼中不需要任何額外的同步或協(xié)調(diào),這個(gè)類都能表現(xiàn)出正確的行為,那么就稱這個(gè)類時(shí)線程安全的。

線程安全主要體現(xiàn)在以下三個(gè)方面:

原子性:提供了互斥訪問,同一時(shí)刻只能有一個(gè)線程對它進(jìn)行操作

可見性:一個(gè)線程對主內(nèi)存的修改可以及時(shí)的被其他線程觀察到

有序性:一個(gè)線程觀察其他線程中的指令執(zhí)行順序,由于指令重排序的存在,該觀察結(jié)果一般雜亂無序

引子

在多線程的場景中,我們需要保證數(shù)據(jù)安全,就會考慮同步的方案,通常會使用synchronized或者lock來處理,使用了synchronized意味著內(nèi)核態(tài)的一次切換。這是一個(gè)很重的操作。

有沒有一種方式,可以比較便利的實(shí)現(xiàn)一些簡單的數(shù)據(jù)同步,比如計(jì)數(shù)器等等。concurrent包下的atomic提供我們這么一種輕量級的數(shù)據(jù)同步的選擇。

使用例子

import java.util.concurrent.CountDownLatch; 
import java.util.concurrent.atomic.AtomicInteger; 
 
public class App { 
 
 public static void main(String[] args) throws Exception { 
  CountDownLatch countDownLatch = new CountDownLatch(100); 
 
  AtomicInteger atomicInteger = new AtomicInteger(0); 
  for (int i = 0; i < 100; i++) { 
   new Thread() { 
    @Override 
    public void run() { 
     atomicInteger.getAndIncrement(); 
 
     countDownLatch.countDown(); 
    } 
   }.start(); 
  } 
 
  countDownLatch.await(); 
 
  System.out.println(atomicInteger.get()); 
 } 
} 

在以上代碼中,使用AtomicInteger聲明了一個(gè)全局變量,并且在多線程中進(jìn)行自增,代碼中并沒有進(jìn)行顯示的加鎖。

以上代碼的輸出結(jié)果,永遠(yuǎn)都是100。如果將AtomicInteger換成Integer,打印結(jié)果基本都是小于100。

也就說明AtomicInteger聲明的變量,在多線程場景中的自增操作是可以保證線程安全的。接下來我們分析下其原理。

原理

我們可以看一下AtomicInteger的代碼

Java并發(fā)編程包中atomic的實(shí)現(xiàn)原理示例詳解

他的值是存在一個(gè)volatile的int里面。volatile只能保證這個(gè)變量的可見性。不能保證他的原子性。

可以看看getAndIncrement這個(gè)類似i++的函數(shù),可以發(fā)現(xiàn),是調(diào)用了UnSafe中的getAndAddInt。

Java并發(fā)編程包中atomic的實(shí)現(xiàn)原理示例詳解

UnSafe是何方神圣?UnSafe提供了java可以直接操作底層的能力。

進(jìn)一步,我們可以發(fā)現(xiàn)實(shí)現(xiàn)方式:

Java并發(fā)編程包中atomic的實(shí)現(xiàn)原理示例詳解

如何保證原子性:自旋 + CAS(樂觀鎖)。在這個(gè)過程中,通過compareAndSwapInt比較更新value值,如果更新失敗,重新獲取舊值,然后更新。

優(yōu)缺點(diǎn)

CAS相對于其他鎖,不會進(jìn)行內(nèi)核態(tài)操作,有著一些性能的提升。但同時(shí)引入自旋,當(dāng)鎖競爭較大的時(shí)候,自旋次數(shù)會增多。cpu資源會消耗很高。

換句話說,CAS+自旋適合使用在低并發(fā)有同步數(shù)據(jù)的應(yīng)用場景。

Java 8做出的改進(jìn)和努力

在Java 8中引入了4個(gè)新的計(jì)數(shù)器類型,LongAdder、LongAccumulator、DoubleAdder、DoubleAccumulator。他們都是繼承于Striped64。

在LongAdder 與AtomicLong有什么區(qū)別?

Atomic*遇到的問題是,只能運(yùn)用于低并發(fā)場景。因此LongAddr在這基礎(chǔ)上引入了分段鎖的概念??梢詤⒖肌禞DK8系列之LongAdder解析》一起看看做了什么。

大概就是當(dāng)競爭不激烈的時(shí)候,所有線程都是通過CAS對同一個(gè)變量(Base)進(jìn)行修改,當(dāng)競爭激烈的時(shí)候,會將根據(jù)當(dāng)前線程哈希到對于Cell上進(jìn)行修改(多段鎖)。

Java并發(fā)編程包中atomic的實(shí)現(xiàn)原理示例詳解

可以看到大概實(shí)現(xiàn)原理是:通過CAS樂觀鎖保證原子性,通過自旋保證當(dāng)次修改的最終修改成功,通過降低鎖粒度(多段鎖)增加并發(fā)性能。

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對創(chuàng)新互聯(lián)的支持。

當(dāng)前名稱:Java并發(fā)編程包中atomic的實(shí)現(xiàn)原理示例詳解
新聞來源:http://muchs.cn/article44/piohhe.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制開發(fā)網(wǎng)站維護(hù)、外貿(mào)建站、企業(yè)建站、網(wǎng)站策劃、Google

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都網(wǎng)站建設(shè)