成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

線程安全性-原子性

mtunique / 974人閱讀

摘要:線程安全性原子性提供了互斥訪問,同一時(shí)刻只能有一個(gè)線程來對(duì)他進(jìn)行操作。原子性包是通過來保證線程原子性通過比較操作的對(duì)象的值工作內(nèi)存的值與底層的值共享內(nèi)存中的值對(duì)比是否相同來判斷是否進(jìn)行處理,如果不相同則重新獲取。

線程安全性 定義
當(dāng)多個(gè)線程訪問同一個(gè)類時(shí),不管運(yùn)行時(shí)環(huán)境采用何種調(diào)度方式,不論線程如何交替執(zhí)行,在主調(diào)代碼中不需要額外的協(xié)同或者同步代碼時(shí),這個(gè)類都可以表現(xiàn)出正確的行為,我們則稱這個(gè)類為線程安全的。
線程安全性

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

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

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

原子性 - Atomic包

AtomicXXX 是通過 CAS(CompareAndSwap)來保證線程原子性 通過比較操作的對(duì)象的值(工作內(nèi)存的值)與底層的值(共享內(nèi)存中的值)對(duì)比是否相同來判斷是否進(jìn)行處理,如果不相同則重新獲取。如此循環(huán)操作,直至獲取到期望的值。

(關(guān)于什么是主內(nèi)存什么事工作內(nèi)存在上篇博客中進(jìn)行介紹了,不懂的同學(xué)可以翻一下)示例代碼:

@Slf4j
public class AtomicExample2 {

    // 請求總數(shù)
    public static int clientTotal = 5000;

    // 同時(shí)并發(fā)執(zhí)行的線程數(shù)
    public static int threadTotal = 200;

    public static AtomicLong count = new AtomicLong(0);

    public static void main(String[] args) throws Exception {
        ExecutorService executorService = Executors.newCachedThreadPool();
        final Semaphore semaphore = new Semaphore(threadTotal);
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
        for (int i = 0; i < clientTotal ; i++) {
            executorService.execute(() -> {
                try {
                    semaphore.acquire();
                    add();
                    semaphore.release();
                } catch (Exception e) {
                    log.error("exception", e);
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
        log.info("count:{}", count.get());
    }

    private static void add() {
        count.incrementAndGet();
        // count.getAndIncrement();
    }
}

LongAdder和DoubleAdder

jdk8中新增的保證同步操作的類,我們之前介紹了AtomicXXX來保證原子性,那么為什么還有有LongAdder呢?
說AtomicXXX的實(shí)現(xiàn)是通過死循環(huán)來判斷值的,在低并發(fā)的情況下AtomicXXX進(jìn)行更改值的命中率還是很高的。但是在高并發(fā)下進(jìn)行命中率可能沒有那么高,從而一直執(zhí)行循環(huán)操作,此時(shí)存在一定的性能消耗,在jvm中我們允許將64位的數(shù)值拆分成2個(gè)32位的數(shù)進(jìn)行儲(chǔ)存的,LongAdder的思想就是將熱點(diǎn)數(shù)據(jù)分離,將AtomicXXX中的核心數(shù)據(jù)分離,熱點(diǎn)數(shù)據(jù)會(huì)被分離成多個(gè)數(shù)組,每個(gè)數(shù)據(jù)都多帶帶維護(hù)各自的值,將單點(diǎn)的并行壓力發(fā)散到了各個(gè)節(jié)點(diǎn),這樣就提高了并行,在低并發(fā)的時(shí)候性能基本和AtomicXXX相同,在高并發(fā)時(shí)具有較好的性能,缺點(diǎn)是在并發(fā)更新時(shí)統(tǒng)計(jì)時(shí)可能會(huì)出現(xiàn)誤差。在低并發(fā),需要全局唯一,準(zhǔn)確的比如id等使用AtomicXXX,要求性能使用LongAdder

@Slf4j
public class AtomicExample3 {

    // 請求總數(shù)
    public static int clientTotal = 5000;

    // 同時(shí)并發(fā)執(zhí)行的線程數(shù)
    public static int threadTotal = 200;

    public static LongAdder count = new LongAdder();

    public static void main(String[] args) throws Exception {
        ExecutorService executorService = Executors.newCachedThreadPool();
        final Semaphore semaphore = new Semaphore(threadTotal);
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);、】【poiuytrewq;"
        
        for (int i = 0; i < clientTotal ; i++) {
            executorService.execute(() -> {
                try {
                    semaphore.acquire();
                    add();
                    semaphore.release();
                } catch (Exception e) {
                    log.error("exception", e);
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
        log.info("count:{}", count);
    }

    private static void add() {
        count.increment();
    }
}

AtomicReference、AtomicReferenceFieldUpdater
AtomicReference是給定指定的期望值當(dāng)期望值與主內(nèi)存中的值相同然后更新,示例代碼

@Slf4j
public class AtomicExample4 {

    private static AtomicReference count = new AtomicReference<>(0);

    public static void main(String[] args) {
        count.compareAndSet(0, 2); // 2
        count.compareAndSet(0, 1); // no
        count.compareAndSet(1, 3); // no
        count.compareAndSet(2, 4); // 4
        count.compareAndSet(3, 5); // no
        log.info("count:{}", count.get());
    }
}
AtomMNBVCXZenceFieldUpdater主要是更新某一個(gè)實(shí)例對(duì)象的一個(gè)字段這個(gè)字段必須是用volatile修飾同時(shí)不能是private修飾的,·157-=·   123444457890-
@Slf4j
public class AtomicExample5 {

    private static AtomicIntegerFieldUpdater updater =
            AtomicIntegerFieldUpdater.newUpdater(AtomicExample5.class, "count");

    @Getter
    public volatile int count = 100;

    public static void main(String[] args) {

        AtomicExample5 example5 = new AtomicExample5();

        if (updater.compareAndSet(example5, 100, 120)) {
            log.info("update success 1, {}", example5.getCount());
        }

        if (updater.compareAndSet(example5, 100, 120)) {
            log.info("update success 2, {}", example5.getCount());
        } else {
            log.info("update failed, {}", example5.getCount());
        }
    }
}

最后我們介紹一下使用AtomicBoolean來實(shí)現(xiàn)只執(zhí)行一次的操作,我們使用private static AtomicBoolean isHappened = new AtomicBoolean(false)來初始化一個(gè)具有原子性的一個(gè)Boolean的記錄是否已經(jīng)被執(zhí)行

@Slf4j
public class AtomicExample6 {

    private static AtomicBoolean isHappened = new AtomicBoolean(false);

    // 請求總數(shù)
    public static int clientTotal = 5000;

    // 同時(shí)并發(fā)執(zhí)行的線程數(shù)
    public static int threadTotal = 200;

    public static void main(String[] args) throws Exception {
        ExecutorService executorService = Executors.newCachedThreadPool();
        final Semaphore semaphore = new Semaphore(threadTotal);
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
        for (int i = 0; i < clientTotal ; i++) {
            executorService.execute(() -> {
                try {
                    semaphore.acquire();
                    test();
                    semaphore.release();
                } catch (Exception e) {
                    log.error("exception", e);
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
        log.info("isHappened:{}", isHappened.get());
    }

    private static void test() {
        if (isHappened.compareAndSet(false, true)) {
            log.info("execute");
        }
    }
}
原子性 - 鎖
我們除了可以使用Atomic包還可以使用鎖來實(shí)現(xiàn)。

synchronize:依賴jvm

修飾代碼塊:適用范圍大括號(hào)括起來的代碼,作用于調(diào)用的對(duì)象

修飾方法:適用范圍整個(gè)方法,作用于調(diào)用的對(duì)象

修飾靜態(tài)方法:適用范圍整個(gè)靜態(tài)方法,作用于所有對(duì)象

修飾一個(gè)類:適用范圍是括起來的部分,作用于所有對(duì)象

Lock:依賴特殊的cpu指令、代碼實(shí)現(xiàn),ReentrantLock

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/74433.html

相關(guān)文章

  • 線程基礎(chǔ)必要知識(shí)點(diǎn)!看了學(xué)習(xí)多線程事半功倍

    摘要:是需要我們?nèi)ヌ幚砗芏嗍虑?,為了防止多線程給我們帶來的安全和性能的問題下面就來簡單總結(jié)一下我們需要哪些知識(shí)點(diǎn)來解決多線程遇到的問題。 前言 不小心就鴿了幾天沒有更新了,這個(gè)星期回家咯。在學(xué)校的日子要努力一點(diǎn)才行! 只有光頭才能變強(qiáng) 回顧前面: 多線程三分鐘就可以入個(gè)門了! Thread源碼剖析 本文章的知識(shí)主要參考《Java并發(fā)編程實(shí)戰(zhàn)》這本書的前4章,這本書的前4章都是講解并發(fā)的基...

    YPHP 評(píng)論0 收藏0
  • Java并發(fā)編程之原子操作

    摘要:將與當(dāng)前線程建立一對(duì)一關(guān)系的值移除。為了讓方法里的操作具有原子性,也就是在一個(gè)線程執(zhí)行這一系列操作的同時(shí)禁止其他線程執(zhí)行這些操作,提出了鎖的概念。 上頭一直在說以線程為基礎(chǔ)的并發(fā)編程的好處了,什么提高處理器利用率啦,簡化編程模型啦。但是磚家們還是認(rèn)為并發(fā)編程是程序開發(fā)中最不可捉摸、最詭異、最扯犢子、最麻煩、最惡心、最心煩、最容易出錯(cuò)、最不符合社會(huì)主義核心價(jià)值觀的一個(gè)部分~ 造成這么多最...

    instein 評(píng)論0 收藏0
  • 【Java并發(fā)】線程安全

    摘要:另一個(gè)是使用鎖的機(jī)制來處理線程之間的原子性。依賴于去實(shí)現(xiàn)鎖,因此在這個(gè)關(guān)鍵字作用對(duì)象的作用范圍內(nèi),都是同一時(shí)刻只能有一個(gè)線程對(duì)其進(jìn)行操作的。 線程安全性 定義:當(dāng)多個(gè)線程訪問某個(gè)類時(shí),不管運(yùn)行時(shí)環(huán)境采用何種調(diào)度方式或者這些線程將如何交替執(zhí)行,并且在主調(diào)代碼中不需要任何額外的同步或協(xié)同,這個(gè)類都能表現(xiàn)出正確的行為,那么就稱這個(gè)類是線程安全的。 線程安全性主要體現(xiàn)在三個(gè)方面:原子性、可見性...

    劉玉平 評(píng)論0 收藏0
  • Java - 并發(fā) atomic, synchronization and volatile

    摘要:線程的這種交叉操作會(huì)導(dǎo)致線程不安全。原子操作是在多線程環(huán)境下避免數(shù)據(jù)不一致必須的手段。如果聲明一個(gè)域?yàn)橐恍┣闆r就可以確保多線程訪問到的變量是最新的。并發(fā)要求一個(gè)線程對(duì)對(duì)象進(jìn)行了操作,對(duì)象發(fā)生了變化,這種變化應(yīng)該對(duì)其他線程是可見的。 雖是讀書筆記,但是如轉(zhuǎn)載請注明出處 http://segmentfault.com/blog/exploring/ .. 拒絕伸手復(fù)制黨 一個(gè)問題: ...

    StonePanda 評(píng)論0 收藏0
  • 【J2SE】java并發(fā)基礎(chǔ)

    摘要:的線程機(jī)制是搶占式。會(huì)讓出當(dāng)多個(gè)線程并發(fā)的對(duì)主存中的數(shù)據(jù)進(jìn)行操作時(shí),有且只有一個(gè)會(huì)成功,其余均失敗。和對(duì)象只有在困難的多線程問題中才是必須的。 并發(fā)簡述 并發(fā)通常是用于提高運(yùn)行在單處理器上的程序的性能。在單 CPU 機(jī)器上使用多任務(wù)的程序在任意時(shí)刻只在執(zhí)行一項(xiàng)工作。 并發(fā)編程使得一個(gè)程序可以被劃分為多個(gè)分離的、獨(dú)立的任務(wù)。一個(gè)線程就是在進(jìn)程中的一個(gè)單一的順序控制流。java的線程機(jī)制是...

    tianyu 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<