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

資訊專(zhuān)欄INFORMATION COLUMN

Java多線程學(xué)習(xí)(三)volatile關(guān)鍵字

tain335 / 3180人閱讀

摘要:三關(guān)鍵字能保證原子性嗎并發(fā)編程藝術(shù)這本書(shū)上說(shuō)保證但是在自增操作非原子操作上不保證,多線程編程核心藝術(shù)這本書(shū)說(shuō)不保證。多線程訪問(wèn)關(guān)鍵字不會(huì)發(fā)生阻塞,而關(guān)鍵字可能會(huì)發(fā)生阻塞關(guān)鍵字能保證數(shù)據(jù)的可見(jiàn)性,但不能保證數(shù)據(jù)的原子性。

系列文章傳送門(mén):

Java多線程學(xué)習(xí)(一)Java多線程入門(mén)

Java多線程學(xué)習(xí)(二)synchronized關(guān)鍵字(1)

java多線程學(xué)習(xí)(二)synchronized關(guān)鍵字(2)

Java多線程學(xué)習(xí)(三)volatile關(guān)鍵字

Java多線程學(xué)習(xí)(四)等待/通知(wait/notify)機(jī)制

Java多線程學(xué)習(xí)(五)線程間通信知識(shí)點(diǎn)補(bǔ)充

Java多線程學(xué)習(xí)(六)Lock鎖的使用

Java多線程學(xué)習(xí)(七)并發(fā)編程中一些問(wèn)題

系列文章將被優(yōu)先更新于微信公眾號(hào)“Java面試通關(guān)手冊(cè)”,歡迎廣大Java程序員和愛(ài)好技術(shù)的人員關(guān)注。

本節(jié)思維導(dǎo)圖:

思維導(dǎo)圖源文件+思維導(dǎo)圖軟件關(guān)注微信公眾號(hào):“Java面試通關(guān)手冊(cè)”回復(fù)關(guān)鍵字:“Java多線程”免費(fèi)領(lǐng)取。

一 簡(jiǎn)介 先來(lái)看看維基百科對(duì)“volatile關(guān)鍵字”的定義:

在程序設(shè)計(jì)中,尤其是在C語(yǔ)言、C++、C#和Java語(yǔ)言中,使用volatile關(guān)鍵字聲明的變量或?qū)ο笸ǔ>哂信c優(yōu)化、多線程相關(guān)的特殊屬性。通常,volatile關(guān)鍵字用來(lái)阻止(偽)編譯器認(rèn)為的無(wú)法“被代碼本身”改變的代碼(變量/對(duì)象)進(jìn)行優(yōu)化。如在C語(yǔ)言中,volatile關(guān)鍵字可以用來(lái)提醒編譯器它后面所定義的變量隨時(shí)有可能改變,因此編譯后的程序每次需要存儲(chǔ)或讀取這個(gè)變量的時(shí)候,都會(huì)直接從變量地址中讀取數(shù)。如果沒(méi)有volatile關(guān)鍵字,則編譯器可能優(yōu)化讀取和存儲(chǔ),可能暫時(shí)使用寄存器中的值,如果這個(gè)變量由別的程序更新了的話,將出現(xiàn)不一致的現(xiàn)象。據(jù)

在C環(huán)境中,volatile關(guān)鍵字的真實(shí)定義和適用范圍經(jīng)常被誤解。雖然C++、C#和Java都保留了C中的volatile關(guān)鍵字,但在這些編程語(yǔ)言中volatile的用法和語(yǔ)義卻大相徑庭。

Java中的“volatile關(guān)鍵字”關(guān)鍵字:

在 JDK1.2 之前,Java的內(nèi)存模型實(shí)現(xiàn)總是從主存(即共享內(nèi)存)讀取變量,是不需要進(jìn)行特別的注意的。而在當(dāng)前的 Java 內(nèi)存模型下,線程可以把變量保存本地內(nèi)存(比如機(jī)器的寄存器)中,而不是直接在主存中進(jìn)行讀寫(xiě)。這就可能造成一個(gè)線程在主存中修改了一個(gè)變量的值,而另外一個(gè)線程還繼續(xù)使用它在寄存器中的變量值的拷貝,造成數(shù)據(jù)的不一致

要解決這個(gè)問(wèn)題,就需要把變量聲明為 volatile,這就指示 JVM,這個(gè)變量是不穩(wěn)定的,每次使用它都到主存中進(jìn)行讀取。

二 volatile關(guān)鍵字的可見(jiàn)性

volatile 修飾的成員變量在每次被線程訪問(wèn)時(shí),都強(qiáng)迫從主存(共享內(nèi)存)中重讀該成員變量的值。而且,當(dāng)成員變量發(fā)生變化時(shí),強(qiáng)迫線程將變化值回寫(xiě)到主存(共享內(nèi)存)。這樣在任何時(shí)刻,兩個(gè)不同的線程總是看到某個(gè)成員變量的同一個(gè)值,這樣也就保證了同步數(shù)據(jù)的可見(jiàn)性。

RunThread.java

 private boolean isRunning = true;
 int m;
    public boolean isRunning() {
        return isRunning;
    }
    public void setRunning(boolean isRunning) {
        this.isRunning = isRunning;
    }
    @Override
    public void run() {
        System.out.println("進(jìn)入run了");
        while (isRunning == true) {
            int a=2;
            int b=3;
            int c=a+b;
            m=c;
        }
        System.out.println(m);
        System.out.println("線程被停止了!");
    }
}

Run.java

public class Run {
    public static void main(String[] args) throws InterruptedException {
        RunThread thread = new RunThread();
        
        thread.start();
        Thread.sleep(1000);
        thread.setRunning(false);

        System.out.println("已經(jīng)賦值為false");
    }
}

運(yùn)行結(jié)果:

RunThread類(lèi)中的isRunning變量沒(méi)有加上volatile關(guān)鍵字時(shí),運(yùn)行以上代碼會(huì)出現(xiàn)死循環(huán),這是因?yàn)閕sRunning變量雖然被修改但是沒(méi)有被寫(xiě)到主存中,這也就導(dǎo)致該線程在本地內(nèi)存中的值一直為true,這樣就導(dǎo)致了死循環(huán)的產(chǎn)生。

解決辦法也很簡(jiǎn)單:isRunning變量前加上volatile關(guān)鍵字即可。

這樣運(yùn)行就不會(huì)出現(xiàn)死循環(huán)了。
加上volatile關(guān)鍵字后的運(yùn)行結(jié)果:

你是不是以為到這就完了?

不存在的!?。?/strong>(這里還有一點(diǎn)需要強(qiáng)調(diào),下面的內(nèi)容一定要看,不然你在用volatile關(guān)鍵字時(shí)會(huì)很迷糊,因?yàn)闀?shū)籍幾乎都沒(méi)有提這個(gè)問(wèn)題)

假如你把while循環(huán)代碼里加上任意一個(gè)輸出語(yǔ)句或者sleep方法你會(huì)發(fā)現(xiàn)死循環(huán)也會(huì)停止,不管isRunning變量是否被加上了上volatile關(guān)鍵字。

加上輸出語(yǔ)句:

    while (isRunning == true) {
            int a=2;
            int b=3;
            int c=a+b;
            m=c;
            System.out.println(m);
        }

加上sleep方法:

        while (isRunning == true) {
            int a=2;
            int b=3;
            int c=a+b;
            m=c;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

這是為什么呢?

因?yàn)椋篔VM會(huì)盡力保證內(nèi)存的可見(jiàn)性,即便這個(gè)變量沒(méi)有加同步關(guān)鍵字。換句話說(shuō),只要CPU有時(shí)間,JVM會(huì)盡力去保證變量值的更新。這種與volatile關(guān)鍵字的不同在于,volatile關(guān)鍵字會(huì)強(qiáng)制的保證線程的可見(jiàn)性。而不加這個(gè)關(guān)鍵字,JVM也會(huì)盡力去保證可見(jiàn)性,但是如果CPU一直有其他的事情在處理,它也沒(méi)辦法。最開(kāi)始的代碼,一直處于死循環(huán)中,CPU處于一直占用的狀態(tài),這個(gè)時(shí)候CPU沒(méi)有時(shí)間,JVM也不能強(qiáng)制要求CPU分點(diǎn)時(shí)間去取最新的變量值。而加了輸出或者sleep語(yǔ)句之后,CPU就有可能有時(shí)間去保證內(nèi)存的可見(jiàn)性,于是while循環(huán)可以被終止。

三 volatile關(guān)鍵字能保證原子性嗎?

《Java并發(fā)編程藝術(shù)》這本書(shū)上說(shuō)保證但是在自增操作(非原子操作)上不保證,《Java多線程編程核心藝術(shù)》這本書(shū)說(shuō)不保證。

我個(gè)人更傾向于這種說(shuō)法:volatile無(wú)法保證對(duì)變量原子性的。我個(gè)人感覺(jué)《Java并發(fā)編程藝術(shù)》這本書(shū)上說(shuō)volatile關(guān)鍵字保證原子性嗎但是在自增操作(非原子操作)上不保證這種說(shuō)法是有問(wèn)題的。只是個(gè)人看法,希望不要被噴??梢钥聪旅鏈y(cè)試代碼:

MyThread.java

public class MyThread extends Thread {
    volatile public static int count;

    private static void addCount() {
        for (int i = 0; i < 100; i++) {
            count=i;
        }
        System.out.println("count=" + count);

    }
    @Override
    public void run() {
        addCount();
    }
}

Run.java

public class Run {
    public static void main(String[] args) {
        MyThread[] mythreadArray = new MyThread[100];
        for (int i = 0; i < 100; i++) {
            mythreadArray[i] = new MyThread();
        }

        for (int i = 0; i < 100; i++) {
            mythreadArray[i].start();
        }
    }

}

運(yùn)行結(jié)果:

上面的“count=i;”是一個(gè)原子操作,但是運(yùn)行結(jié)果大部分都是正確結(jié)果99,但是也有部分不是99的結(jié)果。

解決辦法

使用synchronized關(guān)鍵字加鎖。(這只是一種方法,Lock和AtomicInteger原子類(lèi)都可以,因?yàn)橹皩W(xué)過(guò)synchronized關(guān)鍵字,所以我們使用synchronized關(guān)鍵字的方法)

修改MyThread.java如下:

public class MyThread extends Thread {
    public static int count;

    synchronized private static void addCount() {
        for (int i = 0; i < 100; i++) {
            count=i;
        }
        System.out.println("count=" + count);
    }
    @Override
    public void run() {
        addCount();
    }
}

這樣運(yùn)行輸出的count就都為99了,所以要保證數(shù)據(jù)的原子性還是要使用synchronized關(guān)鍵字。

四 synchronized關(guān)鍵字和volatile關(guān)鍵字比較

volatile關(guān)鍵字是線程同步的輕量級(jí)實(shí)現(xiàn),所以volatile性能肯定比synchronized關(guān)鍵字要好。但是volatile關(guān)鍵字只能用于變量而synchronized關(guān)鍵字可以修飾方法以及代碼塊。synchronized關(guān)鍵字在JavaSE1.6之后進(jìn)行了主要包括為了減少獲得鎖和釋放鎖帶來(lái)的性能消耗而引入的偏向鎖和輕量級(jí)鎖以及其它各種優(yōu)化之后執(zhí)行效率有了顯著提升,實(shí)際開(kāi)發(fā)中使用synchronized關(guān)鍵字還是更多一些

多線程訪問(wèn)volatile關(guān)鍵字不會(huì)發(fā)生阻塞,而synchronized關(guān)鍵字可能會(huì)發(fā)生阻塞

volatile關(guān)鍵字能保證數(shù)據(jù)的可見(jiàn)性,但不能保證數(shù)據(jù)的原子性。synchronized關(guān)鍵字兩者都能保證。

volatile關(guān)鍵字用于解決變量在多個(gè)線程之間的可見(jiàn)性,而ynchronized關(guān)鍵字解決的是多個(gè)線程之間訪問(wèn)資源的同步性。

參考:
《Java多線程編程核心技術(shù)》

《Java并發(fā)編程的藝術(shù)》

極客學(xué)院Java并發(fā)編程wiki: http://wiki.jikexueyuan.com/p...

如果你覺(jué)得博主的文章不錯(cuò),歡迎轉(zhuǎn)發(fā)點(diǎn)贊。你能從中學(xué)到知識(shí)就是我最大的幸運(yùn)。

歡迎關(guān)注我的微信公眾號(hào):“Java面試通關(guān)手冊(cè)”(分享各種Java學(xué)習(xí)資源,面試題,以及企業(yè)級(jí)Java實(shí)戰(zhàn)項(xiàng)目回復(fù)關(guān)鍵字免費(fèi)領(lǐng)取)。另外我創(chuàng)建了一個(gè)Java學(xué)習(xí)交流群(群號(hào):174594747),歡迎大家加入一起學(xué)習(xí),這里更有面試,學(xué)習(xí)視頻等資源的分享。

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

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

相關(guān)文章

  • 線程學(xué)習(xí)筆記(1):volatile和synchronized

    摘要:今天開(kāi)始整理學(xué)習(xí)多線程的知識(shí),談?wù)勛钪匾膬蓚€(gè)關(guān)鍵字和。但是這樣一個(gè)過(guò)程比較慢,在使用多線程的時(shí)候就會(huì)出現(xiàn)問(wèn)題。有序性有序性是指多線程執(zhí)行結(jié)果的正確性。這種機(jī)制在多線程中會(huì)出現(xiàn)問(wèn)題,因此可以通過(guò)來(lái)禁止重排。 今天開(kāi)始整理學(xué)習(xí)多線程的知識(shí),談?wù)勛钪匾膬蓚€(gè)關(guān)鍵字:volatile和synchronized。 一、三個(gè)特性 1、原子性 所謂原子性操作就是指這些操作是不可中斷的,要么執(zhí)行過(guò)程...

    jk_v1 評(píng)論0 收藏0
  • JAVA線程機(jī)制解析-volatile&synchronized

    摘要:當(dāng)一個(gè)線程持有重量級(jí)鎖時(shí),另外一個(gè)線程就會(huì)被直接踢到同步隊(duì)列中等待。 java代碼先編譯成字節(jié)碼,字節(jié)碼最后編譯成cpu指令,因此Java的多線程實(shí)現(xiàn)最終依賴(lài)于jvm和cpu的實(shí)現(xiàn) synchronized和volatile 我們先來(lái)討論一下volatile關(guān)鍵字的作用以及實(shí)現(xiàn)機(jī)制,每個(gè)線程看到的用volatile修飾的變量的值都是最新的,更深入的解釋就涉及到Java的內(nèi)存模型了,我們...

    dendoink 評(píng)論0 收藏0
  • 線程基礎(chǔ)必要知識(shí)點(diǎn)!看了學(xué)習(xí)線程事半功倍

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

    YPHP 評(píng)論0 收藏0
  • Java內(nèi)存模型中volatile的內(nèi)存語(yǔ)義及對(duì)同步的作用

    摘要:一接觸內(nèi)存模型中的實(shí)例靜態(tài)變量以及數(shù)組都存儲(chǔ)在堆內(nèi)存中,可在線程之間共享。所以,在編碼上實(shí)現(xiàn)鎖的內(nèi)存語(yǔ)義,可以通過(guò)對(duì)一個(gè)變量的讀寫(xiě),來(lái)實(shí)現(xiàn)線程之間相互通知,保證臨界區(qū)域代碼的互斥執(zhí)行。 原文發(fā)表于我的博客 volatile關(guān)鍵字: 使用volatile關(guān)鍵字修飾的的變量,總能看到任意線程對(duì)它最后的寫(xiě)入,即總能保證任意線程在讀寫(xiě)volatile修飾的變量時(shí),總是從內(nèi)存中讀取最新的值。以下...

    QLQ 評(píng)論0 收藏0
  • Java 線程volatile 解釋

    摘要:支持多線程,中創(chuàng)建線程的方式有兩種繼承類(lèi),重寫(xiě)方法。多線程編程很常見(jiàn)的情況下是希望多個(gè)線程共享資源,通過(guò)多個(gè)線程同時(shí)消費(fèi)資源來(lái)提高效率,但是新手一不小心很容易陷入一個(gè)編碼誤區(qū)。所以,在進(jìn)行多線程編程的時(shí)候一定要留心多個(gè)線程是否共享資源。 文章首發(fā)于 http://jaychen.cc作者 JayChen showImg(https://segmentfault.com/img/remo...

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

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

0條評(píng)論

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