国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Java多線程之volatile

ZweiZhao / 2318人閱讀

摘要:多線程是一個(gè)龐大的知識(shí)體系,這里對(duì)其中的進(jìn)行一個(gè)總結(jié),理清他的來龍去脈。替換重量級(jí)鎖在中又稱為重量級(jí)鎖,能夠保重的幾大特性一致性,原子性,可見性。

Java多線程是一個(gè)龐大的知識(shí)體系,這里對(duì)其中的volatile進(jìn)行一個(gè)總結(jié),理清他的來龍去脈。

CPU緩存

要搞懂volatile,首先得了解CPU在運(yùn)行過程中的存儲(chǔ)是如何處理的,其結(jié)構(gòu)如圖

CPU會(huì)把一些經(jīng)常使用的數(shù)據(jù)緩存在cache中,避免每次都去訪問較慢的memory。在單線程環(huán)境下,如果一個(gè)變量的修改都在cache中,自然不會(huì)有什么問題,可是在多線程環(huán)境中就可能是下面這個(gè)圖的示意圖(單核另當(dāng)別論)

CPU1 修改了一個(gè)變量a存入cache1,但是CPU2 在cache2中看到的a任然是之前的a,所以造成CPU1修改失效,我們來看看示例代碼:

import java.util.concurrent.TimeUnit;

public class Counter {
    private static  boolean stop ;
    //private static volatile boolean stop ;
    public static void main(String[] args) throws Exception {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                int i = 0;
                while (!stop) {
                    i++;
                }
            }
        } );
        t.start();

        TimeUnit.MILLISECONDS .sleep(5);
        stop = true;
    }
}

在我的4核筆記本上運(yùn)行結(jié)果:

就一直運(yùn)行著,沒有停止(需要手工停止),這說明在主線程中修改的stop變量后,線程t沒有讀取到最新的stop的值,還一直是false。

volatile原理

volatile的原理就是,如果CPU1修改了一個(gè)變量a,不僅要修改自身的cache,還要同步到memory中去,并且使CPU2的cache中的變量a失效,如果CPU2要讀取a,那么就必須到memory中去讀取,這樣就保證了不同的線程之間對(duì)于a的可見性,亦即,無論哪個(gè)線程,隨時(shí)都能獲得變量a最新的最新值。
我們來看看示例代碼:

import java.util.concurrent.TimeUnit;

public class Counter {
    //private static  boolean stop ;
    private static volatile boolean stop ;
    public static void main(String[] args) throws Exception {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                int i = 0;
                while (!stop) {
                    i++;
                }
            }
        } );
        t.start();

        TimeUnit.MILLISECONDS .sleep(5);
        stop = true;
    }
}

在我的4核筆記本上運(yùn)行結(jié)果:

很快程序就結(jié)束了,說明線程t讀到了經(jīng)主線程修改后的stop變量,然后就停止了。

(例子源于《effective Java》)

volatile使用場(chǎng)景 狀態(tài)標(biāo)志

就像上面的代碼里,把簡(jiǎn)單地volatile變量作為狀態(tài)標(biāo)志,來達(dá)成線程之間通訊的目的,省去了用synchronized還要wait,notify或者interrupt的編碼麻煩。

替換重量級(jí)鎖

在Java中synchronized 又稱為重量級(jí)鎖,能夠保重JMM的幾大特性:一致性,原子性,可見性。但是由于使用了鎖操作,在一定程度上會(huì)有更高的性能消耗(鎖的線程互斥性亦即資源消耗)。而volatile能提供可見性,原子性(單個(gè)變量操作,不是a++這種符合操作),所以在讀寫上,可以用volatile來替換synchronized的讀操作,而寫操作仍然有synchronized實(shí)現(xiàn),能取得更好的性能。

import java.util.ArrayList;
import java.util.List;

public class Counter1 {

    private class Count11 {
        private  int value;
        public synchronized int getValue() {
            return value;
        }
        public synchronized int increment() {
            return value++;
        }
    }

//    private class Count11 {
//        private volatile int value=0;
//        int getValue() {  return value;    }
//        synchronized int increment() {    return value++;    }
//    }

    public static void main(String[] args) throws Exception {
        Counter1.Count11 count11 = new Counter1().new Count11();
        List threadArrayList = new ArrayList<>();
        final int[] a = {0};
        Long allTime = 0l;
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 4; i++) {
            Thread t = new Thread(() -> {
                int b = 0;
                for (int j = 0; j < 10000; j++) {
                    count11.increment();
                    a[0] = count11.getValue();
                }
                for (int j = 0; j < 10000; j++) {
                    b++;
                    a[0] = count11.getValue();
                }
            });
            t.start();
            threadArrayList.add(t);
        }
        for (Thread t : threadArrayList) {
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        long endTime = System.currentTimeMillis();
        allTime = ((endTime - startTime));
        System.out.println("result: " + a[0] + ", average time: " + (allTime) + "ms");



    }

}

volatile優(yōu)化結(jié)果:

result: 40000, average time: 124ms
result: 40000, average time: 133ms
result: 40000, average time: 141ms
result: 40000, average time: 112ms
result: 40000, average time: 123ms
result: 40000, average time: 143ms
result: 40000, average time: 120ms
result: 40000, average time: 120ms

未優(yōu)化結(jié)果:

result: 40000, average time: 144ms
result: 40000, average time: 150ms
result: 40000, average time: 149ms
result: 40000, average time: 165ms
result: 40000, average time: 134ms
result: 40000, average time: 132ms
result: 40000, average time: 157ms
result: 40000, average time: 138ms
result: 40000, average time: 158ms

可見使用volatile過后效果的確優(yōu)于只使用synchronized的性能,不過試驗(yàn)中發(fā)現(xiàn)有個(gè)閾值,如果讀取修改次數(shù)較小,比如1000以內(nèi),只使用synchronized效果略好,存取次數(shù)變大以后 volatile的優(yōu)勢(shì)才慢慢體現(xiàn)出來(次數(shù)達(dá)到10000的話,差距就在60ms左右)。

待挖掘

還有很多用法,在將來的學(xué)習(xí)中,不斷總結(jié)與挖掘。

聯(lián)想

無論處于應(yīng)用的哪一層,優(yōu)化的思路都是可以相互借鑒的,比如我們做一個(gè)服務(wù)集群,如果每一個(gè)節(jié)點(diǎn)都要保存所有用戶的session,就很難使得session同步,我們就可以借鑒volatile這種思路,在集群之上搞一個(gè)調(diào)度器,如果某一個(gè)節(jié)點(diǎn)修改了一個(gè)用戶session,就報(bào)告給調(diào)度器,然后調(diào)度器通知其他所有節(jié)點(diǎn)修改該用戶session。而一般情況下,數(shù)據(jù)的讀寫比都比較高,所以這樣做就能到達(dá)一個(gè)很好的性能。

注意事項(xiàng)

引用類型的volatile只在引用本身發(fā)生變化時(shí)具有可見性,其引用的對(duì)象的元素發(fā)生變化時(shí)不具有可見性

歡迎訪問我的個(gè)人主頁 mageek(mageek.cn)

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/67040.html

相關(guān)文章

  • Java貓說】Java線程內(nèi)存可見性(下篇)

    摘要:閱讀本文約分鐘上一次我們說到互斥代碼的實(shí)現(xiàn)過程,如果有忘記或不清楚的可以去上篇看看。貓說多線程之內(nèi)存可見性上篇今天我們了解下重排序。 閱讀本文約3分鐘 上一次我們說到synchronized互斥代碼的實(shí)現(xiàn)過程,如果有忘記或不清楚的可以去上篇看看?!綣ava貓說】Java多線程之內(nèi)存可見性(上篇) 今天我們了解下重排序。 其使代碼書寫的順序與實(shí)現(xiàn)執(zhí)行的順序不同,指令重排序是編譯器或處理...

    elliott_hu 評(píng)論0 收藏0
  • 慕課網(wǎng)_《細(xì)說Java線程內(nèi)存可見性》學(xué)習(xí)總結(jié)

    時(shí)間:2017年07月09日星期日說明:本文部分內(nèi)容均來自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.com教學(xué)源碼:無學(xué)習(xí)源碼:https://github.com/zccodere/s... 第一章:課程簡(jiǎn)介 1-1 課程簡(jiǎn)介 課程目標(biāo)和學(xué)習(xí)內(nèi)容 共享變量在線程間的可見性 synchronized實(shí)現(xiàn)可見性 volatile實(shí)現(xiàn)可見性 指令重排序 as-if-seria...

    wupengyu 評(píng)論0 收藏0
  • 死磕 java同步系列volatile解析

    摘要:前半句是指線程內(nèi)表現(xiàn)為串行的語義,后半句是指指令重排序現(xiàn)象和工作內(nèi)存和主內(nèi)存同步延遲現(xiàn)象。關(guān)于內(nèi)存模型的講解請(qǐng)參考死磕同步系列之。目前國(guó)內(nèi)市面上的關(guān)于內(nèi)存屏障的講解基本不會(huì)超過這三篇文章,包括相關(guān)書籍中的介紹。問題 (1)volatile是如何保證可見性的? (2)volatile是如何禁止重排序的? (3)volatile的實(shí)現(xiàn)原理? (4)volatile的缺陷? 簡(jiǎn)介 volatile...

    番茄西紅柿 評(píng)論0 收藏0
  • 死磕 java同步系列volatile解析

    摘要:前半句是指線程內(nèi)表現(xiàn)為串行的語義,后半句是指指令重排序現(xiàn)象和工作內(nèi)存和主內(nèi)存同步延遲現(xiàn)象。關(guān)于內(nèi)存模型的講解請(qǐng)參考死磕同步系列之。目前國(guó)內(nèi)市面上的關(guān)于內(nèi)存屏障的講解基本不會(huì)超過這三篇文章,包括相關(guān)書籍中的介紹。問題 (1)volatile是如何保證可見性的? (2)volatile是如何禁止重排序的? (3)volatile的實(shí)現(xiàn)原理? (4)volatile的缺陷? 簡(jiǎn)介 volatile...

    番茄西紅柿 評(píng)論0 收藏0
  • 死磕 java同步系列volatile解析

    摘要:前半句是指線程內(nèi)表現(xiàn)為串行的語義,后半句是指指令重排序現(xiàn)象和工作內(nèi)存和主內(nèi)存同步延遲現(xiàn)象。關(guān)于內(nèi)存模型的講解請(qǐng)參考死磕同步系列之。目前國(guó)內(nèi)市面上的關(guān)于內(nèi)存屏障的講解基本不會(huì)超過這三篇文章,包括相關(guān)書籍中的介紹。問題 (1)volatile是如何保證可見性的? (2)volatile是如何禁止重排序的? (3)volatile的實(shí)現(xiàn)原理? (4)volatile的缺陷? 簡(jiǎn)介 volatile...

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

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

0條評(píng)論

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