最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

volatile可見性的一些認(rèn)識和論證

 更新時間:2017年08月24日 08:27:58   作者:陳其苗  
volatile的關(guān)鍵詞的使用在JVM內(nèi)存模型中已是老生常談了,這篇文章主要結(jié)合自己對可見性的一些認(rèn)識和一些直觀的例子來談?wù)剉olatile,感興趣的朋友一起看看吧

一、前言

    volatile的關(guān)鍵詞的使用在JVM內(nèi)存模型中已是老生常談了,這篇文章主要結(jié)合自己對可見性的一些認(rèn)識和一些直觀的例子來談?wù)剉olatile。文章正文大致分為三部分,首先會介紹一下happen-before,接著講解volatile的一些使用場景,最后會附上一些例子來論證使用與不使用volatile的區(qū)別。

二、happen-before

    對操作系統(tǒng)有認(rèn)識的同學(xué)一定知道,CPU一般有三級緩存,在與內(nèi)存交互的時候,存在緩存與內(nèi)存的更新問題,其次CPU在讀取指令的時候,會做一些指令重排序的工作,提高程序運行效率。類比JVM內(nèi)存模型(見下圖),每個線程擁有自己的工作內(nèi)存,同時存在一個主存,線程間通過主存來進(jìn)行通信,同樣的,JVM也存在指令重排序,可見JVM內(nèi)存模型與實際物理內(nèi)存模型十分相似。(這里順便提一下,編譯器其實也會作一定重排序優(yōu)化)。

    作為開發(fā)人員,你不可能了解到每個JVM優(yōu)化細(xì)節(jié),更不可能了解到CPU何時會進(jìn)行指令重排序,所以java語言定義了更上層的一個概念,就是"happen-before"。起初,我看到這個單詞的時候,誤以為這是一個指令執(zhí)行順序的規(guī)則,后來仔細(xì)想想又發(fā)覺不對勁。如果”happen-before“僅僅是抽象了指令執(zhí)行順序的概念,那么它就把握不了“工作內(nèi)存將值寫回主存”和“工作內(nèi)存從主存中刷新自己的值”這個兩個action的時機(jī)。那么這個概念也就變得沒什么意義了。所以!所以!所以!”happen-before“是一個可見性的原則?。?!

下面給出happen-before的具體規(guī)則:

程序次序規(guī)則:一個線程內(nèi),按照代碼順序,書寫在前面的操作先行發(fā)生于書寫在后面的操作;

鎖定規(guī)則:一個unLock操作先行發(fā)生于后面對同一個鎖額lock操作;

volatile變量規(guī)則:對一個變量的寫操作先行發(fā)生于后面對這個變量的讀操作;

傳遞規(guī)則:如果操作A先行發(fā)生于操作B,而操作B又先行發(fā)生于操作C,則可以得出操作A先行發(fā)生于操作C;

線程啟動規(guī)則:Thread對象的start()方法先行發(fā)生于此線程的每個一個動作;

線程中斷規(guī)則:對線程interrupt()方法的調(diào)用先行發(fā)生于被中斷線程的代碼檢測到中斷事件的發(fā)生;

線程終結(jié)規(guī)則:線程中所有的操作都先行發(fā)生于線程的終止檢測,我們可以通過Thread.join()方法結(jié)束、Thread.isAlive()的返回值手段檢測到線程已經(jīng)終止執(zhí)行;

對象終結(jié)規(guī)則:一個對象的初始化完成先行發(fā)生于他的finalize()方法的開始;

三、volatile的使用場景

    happen-before的第三條規(guī)則提到“volatile變量規(guī)則:對一個變量的寫操作先行發(fā)生于后面對這個變量的讀操作”,也就是說;一個volatile變量的寫操作對后續(xù)對讀操作可見。說白了就是每次寫完volatile變量,都會將值從工作內(nèi)存寫回到主存中去,每次讀取volatile變量,工作內(nèi)存必須從主存中刷新下自己的值。如此的話,volatile就是為了解決多個線程共享數(shù)據(jù)的可見性問題。但是不是任何數(shù)據(jù)共享場景都可以使用volatile,必須滿足以下兩種情景才行。

    應(yīng)用場景:

    1.多個線程不依賴原值的情況下進(jìn)行讀寫操作

    2.一個線程依賴原值進(jìn)行寫操作,多個線程進(jìn)行讀操作

在我看來,除了這兩種情況外,無非是多個線程依賴原值進(jìn)行運算,這樣子倒不是說volatile可見性不起作用了,而是無法保證讀取原值和運算是一個原子操作!舉個簡單的例子,多個線程執(zhí)行i++;i是一個共享變量,由于讀取i的值和i自增不是一個原子操作,所以i最終會丟失掉一部分自增過程。代碼如下,最終i輸出的結(jié)果是一個小于1000的整數(shù)。

/**
 * Created by chenqimiao on 17/8/23.
 */
public class Testv {
  public static volatile int i = 0;
  public static void main(String args[]){
    for (int i =0;i<1000;i++){
      new Thread(){
        public void run(){
          Thread.yield();
          Testv.i++;
        }
      }.start();
    }
    System.out.println(Testv.i);
  }
}

要滿足以上這種需求,我們還必須賦予代碼原子性,最常用的肯定是鎖操作了,一個字穩(wěn),性能可觀,同時保證原子性和可見性。如果想操作一波的話,還可以考慮使用一些無鎖操作,如CAS,象java.util.concurrent包下的一些原子類就是利用了CAS來做到原子性,但原子性并不能保證可見性,這個時候,還需要配合volatile。

以上種種都是對volatile使用場景的概括,想了解具體的使用場景可以參考博文:https://www.ibm.com/developerworks/cn/java/j-jtp06197.html

四、volatile可見性的證明

   先上段代碼好了,不知道從何說起了。

package com.example.demo.netty;
/**
 * Created with IntelliJ IDEA.
 * User: chenqimiao
 * Date: 2017/8/23
 * Time: 9:16
 * To change this template use File | Settings | File Templates.
 */
public class VolatileTest {
   boolean isStop = false;
  public void test(){
    Thread t1 = new Thread(){
      public void run() {
        isStop=true;
      }
    };
    Thread t2 = new Thread(){
      public void run() {
        while (!isStop);
      }
    };
    t2.start();
    t1.start();
  }
  public static void main(String args[]) throws InterruptedException {
    for (int i =0;i<25;i++){
      new VolatileTest().test();
    }
  }
}

    上面這段代碼可能永遠(yuǎn)也不會結(jié)束,因為線程一對isStop的賦值,線程二可能對此并不可見。當(dāng)然只是可能,所以為了放大可見性問題,我這里作了25次循環(huán)。只要有一組線程,“線程一對isStop的賦值,線程二對此不可見”的情況發(fā)生,就不會退出程序。

    now,假如你給 isStop 添加一個 volatile 關(guān)鍵字,那么你會發(fā)現(xiàn)程序立馬就會退出。

總結(jié)

以上所述是小編給大家介紹的volatile可見性的一些認(rèn)識和論證,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!

相關(guān)文章

  • Java中instanceof關(guān)鍵字的用法總結(jié)

    Java中instanceof關(guān)鍵字的用法總結(jié)

    instanceof是Java的一個二元操作符,和==,>,<是同一類東東。由于它是由字母組成的,所以也是Java的保留關(guān)鍵字。它的作用是測試它左邊的對象是否是它右邊的類的實例,返回boolean類型的數(shù)據(jù)
    2013-10-10
  • IDEA部署Tomcat的超詳細(xì)圖文教程

    IDEA部署Tomcat的超詳細(xì)圖文教程

    最近迫于無奈從我哪破舊的Eclipse轉(zhuǎn)換到了IDEA,然后就是超多的不習(xí)慣,下面這篇文章主要給大家介紹了關(guān)于IDEA部署Tomcat的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2023-02-02
  • 深入理解Maven的坐標(biāo)與依賴

    深入理解Maven的坐標(biāo)與依賴

    這篇文章主要介紹了深入理解Maven的坐標(biāo)與依賴,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-01-01
  • Java程序員需要掌握的英語詞組

    Java程序員需要掌握的英語詞組

    這篇文章主要為大家詳細(xì)匯總了Java程序員需要掌握的英語詞組 ,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-04-04
  • 詳解SpringBoot是如何保證接口安全的

    詳解SpringBoot是如何保證接口安全的

    對于互聯(lián)網(wǎng)來說,只要你系統(tǒng)的接口會暴露在外網(wǎng),就避免不了接口安全問題。?如果你的接口在外網(wǎng)裸奔,只要讓黑客知道接口的地址和參數(shù)就可以調(diào)用,那簡直就是災(zāi)難。這篇文章主要介紹了SpringBoot保證接口安全的方法,需要的可以參考一下
    2023-02-02
  • 詳解Java設(shè)計模式——命令模式

    詳解Java設(shè)計模式——命令模式

    這篇文章主要介紹了Java設(shè)計模式——命令模式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • SpringBoot?jwt的token如何刷新

    SpringBoot?jwt的token如何刷新

    這篇文章主要給大家介紹了關(guān)于SpringBoot?jwt的token如何刷新的相關(guān)資料,Json web token(JWT)是為了在網(wǎng)絡(luò)應(yīng)用環(huán)境間傳遞聲明而執(zhí)行的一種基于JSON的開放標(biāo)準(zhǔn),需要的朋友可以參考下
    2023-07-07
  • Spring之InitializingBean接口和DisposableBean接口的使用

    Spring之InitializingBean接口和DisposableBean接口的使用

    這篇文章主要介紹了Spring之InitializingBean接口和DisposableBean接口的使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • Java中Map和Set的常見用法舉例

    Java中Map和Set的常見用法舉例

    Map和Set是一種專門用來進(jìn)行搜索的容器或者數(shù)據(jù)結(jié)構(gòu),其具體效率與具體的實例化子類有關(guān),下面這篇文章主要給大家介紹了關(guān)于Java中Map和Set的常見用法,需要的朋友可以參考下
    2024-04-04
  • PowerJob的GridFsManager工作流程源碼解讀

    PowerJob的GridFsManager工作流程源碼解讀

    這篇文章主要為大家介紹了PowerJob的GridFsManager工作流程源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01

最新評論

鄯善县| 剑河县| 漠河县| 永昌县| 通辽市| 林周县| 灵璧县| 芜湖县| 临汾市| 台州市| 木里| 辽宁省| 靖江市| 鄂州市| 绥滨县| 贵阳市| 通州区| 右玉县| 民县| 安庆市| 鲁甸县| 商南县| 大理市| 宁国市| 济阳县| 东宁县| 兴海县| 永顺县| 安远县| 衡南县| 嘉荫县| 疏附县| 温州市| 湘阴县| 方山县| 吴堡县| 万宁市| 临城县| 峨眉山市| 长春市| 泽州县|