程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> 編程綜合問答 >> 線程中止-請教一個JAVA線程的奇怪問題

線程中止-請教一個JAVA線程的奇怪問題

編輯:編程綜合問答
請教一個JAVA線程的奇怪問題

在學習JAVA線程時候的遇到一個很奇怪的現象。讓我們先來看代碼

public class TestThread {

    public static void main(String[] args) {
        IRun ir = new IRun();
        Thread it = new Thread(ir);
        it.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException ex) {
            Logger.getLogger(TestThread.class.getName()).log(Level.SEVERE, null, ex);
        }
        ir.setStop();
    }

    static class IRun implements Runnable {
        boolean exec = true;
        public void setStop() {
            exec = false;
            System.out.println("exec = " + exec);
        }
        @Override
        public void run() {
            int c = 0;
            while (exec) {
                c++;
            }
            System.out.println("退出了循環");
        }
    }
}
     在上述程序首先創建一個Runnable對象ir,然後創建一個線程對象it,通過it.start()啟動線程,執行IRun類中的run()函數,執行一個while循環。while循環的條件由布爾變量exec控制。主程序中等待1秒鐘後,修改exec的值為false,按照正常的邏輯應該是在exec值為false後,循環結束執行下面輸出語句,然後線程結束,程序退出。
    但是,上述代碼在運行後,將不會執行run()函數中的System.out.println("退出了循環");語句,程序一直保持運行。對這種現象,在帖子”關於JAVA線程,請大神幫忙“中still_rain給出的這種現象的原因是線程訪問的同步問題導致,當主線程(main函數所在的線程)中修改變量exec的值後,在創建執行的線程中訪問的exec的值沒有發生變化(或者說可能是主線程、執行線程這兩個線程exec變量是不同的對象,好像是說java會將一些資源在每個線程中復制一份?有待確認)。在exec變量前加上volatile修飾符後,程序運行正常,問題似乎解決。
   現在以上述代碼為基礎,進行一次小小的修改。在run()函數中的while循環中加上一個類對象操作,比如新建一個字符串,則run()函數為
 public void run() {
            int c = 0;
            while (exec) {
                String s = new String("");
                c++;
            }
            System.out.println("退出了循環");
        }
    } 
   運行程序,程序按預期的順序執行,順利結束。這時候不管exec變量是否有volatile修飾符,且只在while循環中存在類對象操作(新建對象、對象函數調用(調用的函數不能返回基本數據類型),以及像System.out.println這樣的操作),程序的運行都很正常,對這種現象就不是上述的同步問題能夠解釋的了。在帖子”關於JAVA線程,請大神幫忙“中still_rain(感謝熱情的回復)從編譯器優化的角度進行了解釋。當while循環中只有簡單的基本數據類型參與運算的時候由於執行速度太快,將while循環編譯成了while(true)語句。導致循環不會退出,從而循環後的輸出不會執行,且程序不會退出。
        為了探究這個奇怪現象的原因,讓我們看看編譯後的字節碼,下圖是用jclasslib查看的字節碼,是修改前的run()函數字節碼。

從圖中可以看到,循環體從aload_0開始,到goto 2結束。控制跳轉的語句是ifeq 15,意思是如果值為0則跳轉到15,否則執行下面的語句。
當將上面的while(exec)語句修改為while(true)後,字節碼為:

由兩圖可以看出,編譯器並沒有將while(exec)語句優化為while(true)。再看修改後的代碼編譯的字節碼:

循環體從aload_0起,到goto 2結束。從ifeq 25下面的一行到astotre_2行,為String s = new String("");語句的字節碼,將這段去掉則字節碼與修改前的一樣。所以基本可以排除編譯器優化導致的程序不正常運行。
請看到這篇文章的大神們能夠給予指導,探究出現這種情況的原因,謝謝

最佳回答:


原因找到了,32位JDK下沒有問題,只要是64位JDK都會出現這各現象
(多謝 搞幾年和程序員小董的回復)

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved