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

淺談java指令重排序的問題

 更新時間:2017年09月28日 08:35:50   作者:張升強  
下面小編就為大家?guī)硪黄獪\談java指令重排序的問題。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

指令重排序是個比較復(fù)雜、覺得有些不可思議的問題,同樣是先以例子開頭(建議大家跑下例子,這是實實在在可以重現(xiàn)的,重排序的概率還是挺高的),有個感性的認(rèn)識

/**
 * 一個簡單的展示Happen-Before的例子.
 * 這里有兩個共享變量:a和flag,初始值分別為0和false.在ThreadA中先給  a=1,然后flag=true.
 * 如果按照有序的話,那么在ThreadB中如果if(flag)成功的話,則應(yīng)該a=1,而a=a*1之后a仍然為1,下方的if(a==0)應(yīng)該永遠(yuǎn)不會為
 * 真,永遠(yuǎn)不會打印.
 * 但實際情況是:在試驗100次的情況下會出現(xiàn)0次或幾次的打印結(jié)果,而試驗1000次結(jié)果更明顯,有十幾次打印.
 */
public class SimpleHappenBefore {
 /** 這是一個驗證結(jié)果的變量 */
 private static int a=0;
 /** 這是一個標(biāo)志位 */
 private static boolean flag=false;
 public static void main(String[] args) throws InterruptedException {
  //由于多線程情況下未必會試出重排序的結(jié)論,所以多試一些次
  for(int i=0;i<1000;i++){
   ThreadA threadA=new ThreadA();
   ThreadB threadB=new ThreadB();
   threadA.start();
   threadB.start();
   //這里等待線程結(jié)束后,重置共享變量,以使驗證結(jié)果的工作變得簡單些.
   threadA.join();
   threadB.join();
   a=0;
   flag=false;
  }
 }
 static class ThreadA extends Thread{
  public void run(){
  a=1;
  flag=true;
  }
 }
 static class ThreadB extends Thread{
  public void run(){
   if(flag){
   a=a*1;
   }
   if(a==0){
   System.out.println("ha,a==0");
   }
  }
 }
}

例子比較簡單,也添加了注釋,不再詳細(xì)敘述。

什么是指令重排序?有兩個層面:

在虛擬機(jī)層面,為了盡可能減少內(nèi)存操作速度遠(yuǎn)慢于CPU運行速度所帶來的CPU空置的影響,虛擬機(jī)會按照自己的一些規(guī)則(這規(guī)則后面再敘述)將程序編寫順序打亂——即寫在后面的代碼在時間順序上可能會先執(zhí)行,而寫在前面的代碼會后執(zhí)行——以盡可能充分地利用CPU。拿上面的例子來說:假如不是a=1的操作,而是a=new byte[1024*1024](分配1M空間)`,那么它會運行地很慢,此時CPU是等待其執(zhí)行結(jié)束呢,還是先執(zhí)行下面那句flag=true呢?顯然,先執(zhí)行flag=true可以提前使用CPU,加快整體效率,當(dāng)然這樣的前提是不會產(chǎn)生錯誤(什么樣的錯誤后面再說)。雖然這里有兩種情況:后面的代碼先于前面的代碼開始執(zhí)行;前面的代碼先開始執(zhí)行,但當(dāng)效率較慢的時候,后面的代碼開始執(zhí)行并先于前面的代碼執(zhí)行結(jié)束。不管誰先開始,總之后面的代碼在一些情況下存在先結(jié)束的可能。

在硬件層面,CPU會將接收到的一批指令按照其規(guī)則重排序,同樣是基于CPU速度比緩存速度快的原因,和上一點的目的類似,只是硬件處理的話,每次只能在接收到的有限指令范圍內(nèi)重排序,而虛擬機(jī)可以在更大層面、更多指令范圍內(nèi)重排序。硬件的重排序機(jī)制參見《從JVM并發(fā)看CPU內(nèi)存指令重排序(Memory Reordering)》

重排序很不好理解,上面只是簡單地提了下其場景,要想較好地理解這個概念,需要構(gòu)造一些例子和圖表,在這里介紹兩篇介紹比較詳細(xì)、生動的文章《happens-before俗解》和《深入理解Java內(nèi)存模型(二)——重排序》。其中的“as-if-serial”是應(yīng)該掌握的,即:不管怎么重排序,單線程程序的執(zhí)行結(jié)果不能被改變。編譯器、運行時和處理器都必須遵守“as-if-serial”語義。拿個簡單例子來說,

public void execute(){
 int a=0;
 int b=1;
 int c=a+b;
}

這里a=0,b=1兩句可以隨便排序,不影響程序邏輯結(jié)果,但c=a+b這句必須在前兩句的后面執(zhí)行。

從前面那個例子可以看到,重排序在多線程環(huán)境下出現(xiàn)的概率還是挺高的,在關(guān)鍵字上有volatile和synchronized可以禁用重排序,除此之外還有一些規(guī)則,也正是這些規(guī)則,使得我們在平時的編程工作中沒有感受到重排序的壞處。

程序次序規(guī)則(Program Order Rule):在一個線程內(nèi),按照代碼順序,書寫在前面的操作先行發(fā)生于書寫在后面的操作。準(zhǔn)確地說應(yīng)該是控制流順序而不是代碼順序,因為要考慮分支、循環(huán)等結(jié)構(gòu)。

監(jiān)視器鎖定規(guī)則(Monitor Lock Rule):一個unlock操作先行發(fā)生于后面對同一個對象鎖的lock操作。這里強調(diào)的是同一個鎖,而“后面”指的是時間上的先后順序,如發(fā)生在其他線程中的lock操作。

volatile變量規(guī)則(Volatile Variable Rule):對一個volatile變量的寫操作發(fā)生于后面對這個變量的讀操作,這里的“后面”也指的是時間上的先后順序。

線程啟動規(guī)則(Thread Start Rule):Thread獨享的start()方法先行于此線程的每一個動作。

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

線程中斷規(guī)則(Thread Interruption Rule):對線程interrupte()方法的調(diào)用優(yōu)先于被中斷線程的代碼檢測到中斷事件的發(fā)生,可以通過Thread.interrupted()方法檢測線程是否已中斷。

對象終結(jié)原則(Finalizer Rule):一個對象的初始化完成(構(gòu)造函數(shù)執(zhí)行結(jié)束)先行發(fā)生于它的finalize()方法的開始。

傳遞性(Transitivity):如果操作A先行發(fā)生于操作B,操作B先行發(fā)生于操作C,那就可以得出操作A先行發(fā)生于操作C的結(jié)論。

正是以上這些規(guī)則保障了happen-before的順序,如果不符合以上規(guī)則,那么在多線程環(huán)境下就不能保證執(zhí)行順序等同于代碼順序,也就是“如果在本線程中觀察,所有的操作都是有序的;如果在一個線程中觀察另外一個線程,則不符合以上規(guī)則的都是無序的”,因此,如果我們的多線程程序依賴于代碼書寫順序,那么就要考慮是否符合以上規(guī)則,如果不符合就要通過一些機(jī)制使其符合,最常用的就是synchronized、Lock以及volatile修飾符。

以上這篇淺談java指令重排序的問題就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 淺談一下Spring的核心基礎(chǔ)IOC與DI

    淺談一下Spring的核心基礎(chǔ)IOC與DI

    這篇文章主要介紹了Spring的核心基礎(chǔ)IOC與DI的詳細(xì)用法,spring技術(shù)是現(xiàn)在企業(yè)開發(fā)中幾乎必備的技術(shù)選型,那么學(xué)好spring就很重要,本篇著重講解spring的核心機(jī)制,IOD與DI,一起來看看吧
    2023-03-03
  • Spring?@bean和@component注解區(qū)別

    Spring?@bean和@component注解區(qū)別

    本文主要介紹了Spring?@bean和@component注解區(qū)別,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • java+selenium爬取圖片簽名的方法

    java+selenium爬取圖片簽名的方法

    這篇文章主要為大家詳細(xì)介紹了java+selenium爬取圖片簽名的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • 使用dom4j解析xml文件問題

    使用dom4j解析xml文件問題

    這篇文章主要介紹了使用dom4j解析xml文件問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • 淺談String.split()遇到空字符串的幾種情況

    淺談String.split()遇到空字符串的幾種情況

    這篇文章主要介紹了淺談String.split()遇到空字符串的幾種情況,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-10-10
  • 怎樣使用PowerMockito 測試靜態(tài)方法

    怎樣使用PowerMockito 測試靜態(tài)方法

    這篇文章主要介紹了使用PowerMockito 測試靜態(tài)的方法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Java常用內(nèi)置注解用法分析

    Java常用內(nèi)置注解用法分析

    這篇文章主要介紹了Java常用內(nèi)置注解用法,結(jié)合實例形式分析了java使用@SuppressWarnings關(guān)閉警告信息以及@Depreca標(biāo)注的元素不使用兩種注解使用方法,需要的朋友可以參考下
    2019-08-08
  • Spring Boot實現(xiàn)文件上傳示例代碼

    Spring Boot實現(xiàn)文件上傳示例代碼

    本篇文章主要介紹了Spring Boot實現(xiàn)文件上傳示例代碼,可以實現(xiàn)單文件和多文件的上傳,具有一定的參考價值,感興趣的小伙伴們可以參考一下。
    2017-03-03
  • 一文帶你掌握J(rèn)ava?SPI的原理和實踐

    一文帶你掌握J(rèn)ava?SPI的原理和實踐

    在Java中,我們經(jīng)常會提到面向接口編程,這樣減少了模塊之間的耦合,更加靈活,Java?SPI?(Service?Provider?Interface)就提供了這樣的機(jī)制,本文就來講講它的原理與具體使用吧
    2023-05-05
  • 詳解JNA中的回調(diào)方法

    詳解JNA中的回調(diào)方法

    這篇文章主要介紹了JNA中的回調(diào)方法,主要包括JNA 中的 Callback,callback 的應(yīng)用,本文通過實例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-05-05

最新評論

宁乡县| 天峨县| 红河县| 托克逊县| 永修县| 仁布县| 诏安县| 祥云县| 山阴县| 萍乡市| 沅江市| 大厂| 瑞昌市| 商都县| 安陆市| 泸定县| 车险| 荥阳市| 桑日县| 洛扎县| 兰考县| 永城市| 清苑县| 图木舒克市| 会理县| 江口县| 确山县| 镶黄旗| 治县。| 札达县| 察哈| 苍山县| 大同市| 息烽县| 登封市| 灵山县| 监利县| 扎赉特旗| 平乡县| 郧西县| 祁东县|