一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 淺談java指令重排序的問題

淺談java指令重排序的問題

2021-01-12 13:58張升強 Java教程

下面小編就為大家帶來一篇淺談java指令重排序的問題。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/**
 * 一個簡單的展示Happen-Before的例子.
 * 這里有兩個共享變量:a和flag,初始值分別為0和false.在ThreadA中先給  a=1,然后flag=true.
 * 如果按照有序的話,那么在ThreadB中如果if(flag)成功的話,則應該a=1,而a=a*1之后a仍然為1,下方的if(a==0)應該永遠不會為
 * 真,永遠不會打印.
 * 但實際情況是:在試驗100次的情況下會出現0次或幾次的打印結果,而試驗1000次結果更明顯,有十幾次打印.
 */
public class SimpleHappenBefore {
 /** 這是一個驗證結果的變量 */
 private static int a=0;
 /** 這是一個標志位 */
 private static boolean flag=false;
 public static void main(String[] args) throws InterruptedException {
  //由于多線程情況下未必會試出重排序的結論,所以多試一些次
  for(int i=0;i<1000;i++){
   ThreadA threadA=new ThreadA();
   ThreadB threadB=new ThreadB();
   threadA.start();
   threadB.start();
   //這里等待線程結束后,重置共享變量,以使驗證結果的工作變得簡單些.
   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");
   }
  }
 }
}

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

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

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

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

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

?
1
2
3
4
5
public void execute(){
 int a=0;
 int b=1;
 int c=a+b;
}

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

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

程序次序規則(Program Order Rule):在一個線程內,按照代碼順序,書寫在前面的操作先行發生于書寫在后面的操作。準確地說應該是控制流順序而不是代碼順序,因為要考慮分支、循環等結構。

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

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

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

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

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

對象終結原則(Finalizer Rule):一個對象的初始化完成(構造函數執行結束)先行發生于它的finalize()方法的開始。

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

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

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

原文鏈接:http://my.oschina.net/004/blog/222069?fromerr=ER2mp62C

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 密臀tv| 精品手机在线视频 | 好大好硬好深好爽想要小雪 | 青青草一区二区免费精品 | 高h肉爽文农民工 | 国产成人精品一区二区仙踪林 | 亚洲大片免费观看 | 亚洲国产精品91 | 国产欧美日韩精品在线 | 九九热在线视频 | 全日爱韩国视频在线观看 | 国产精品资源站 | 2018亚洲男人天堂 | 5x社区在线观看直接进入 | 教室里老师好紧h | 亚洲精品一区二区三区在线播放 | 免费观看网站 | 99re这里只有精品在线观看 | 美女光屁股网站 | 香蕉国产精品偷在线播放 | 天若有情1992国语版完整版 | 91精品国产9l久久久久 | 欧美大陆日韩一区二区三区 | 天生奶水1v1高h | 亚洲天堂男人网 | 和肥岳在厨房激情 | 韩国情事伦理片观看地址 | h片在线看| 国产一级片在线 | 久久婷婷五月免费综合色啪 | 日本阿v精品视频在线观看 日本xxx片免费高清在线 | 欧美日韩高清观看一区二区 | 国产精品久久久久久久久免费hd | 午夜欧美精品久久久久久久久 | 精品久久99麻豆蜜桃666 | 亚洲国产日韩成人综合天堂 | 日本高清在线看 | 国产a一级毛片爽爽影院 | 亚洲图片二区 | 日韩美一区二区三区 | 国内精品伊人久久大香线焦 |