java多線程的兩點誤點(轉)

在使用java線程的時候,特別是初學者總會有幾點很常見的誤區,下面以以下代碼爲例:線程類:
package threadtest1;
public class ReturnThreadInfo extends Thread {
    private String str; 
    public ReturnThreadInfo() {
        this.str = "Hello";
    }
    
    public void run(){
        try{
            this.str = "Hello World!";
        }catch(Exception ex){
            
        }
    }
    
    /*返回線程信息:str變量的值*/
    public String getThreadInfo(){
        return this.str;
    }
}
主類:
package threadtest1;
public class Main extends Thread {
    
    public Main() {
    }
    
    public static void main(String[] args) {
        ReturnThreadInfo returnThreadInfo = new ReturnThreadInfo();
        returnThreadInfo.start();
        System.out.println(returnThreadInfo.getThreadInfo());
    }
}
大家可以看到這個程序主要功能是返回線程returnThreadInfo對象的變量str的值並輸出,那麼str的值到底是什麼,一些人可能會認爲
是"Hello world!"或是null,其實如果大家運行下就會知道輸出的str的值實際是"Hello"。爲什麼呢?其實認爲輸出結果是"Hello world"或是
null的人存在着兩個比較常見的誤區:
1、誤區一:認爲returnThreadInfo對象中的run方法一定在主類的System.out.println(returnThreadInfo.getThreadInfo())之間運行。
   這是比較常見的一個誤區,稍微瞭解一些java編譯原理的人應該清楚,java源文件的代碼編譯是自上而下的,也就是處在同一文件上面的代
碼會在下面的代碼之間被編譯和運行。所以很多人認爲returnThreadInfo.start()先被運行,returnThreadInfo線程被啓動,然後run()方法被
調用,str被賦值:"hello world!",然後線程結束並返回到主類,最後調用System.out.println(returnThreadInfo.getThreadInfo())將str
的值輸出就是"Hello world!"。
   如果returnThreadInfo不是一個線程而是一個普通類的對象,那麼輸出的結果是"Hello world",但是正因爲returnThreadInfo是一個線程
,所以run方法並不一定在System.out.println(returnThreadInfo.getThreadInfo())之前運行。因爲實際上主類Main在運行時也是一個線程,
當調用returnThreadInfo.start()方法來啓動returnThreadInfo線程後,此時系統中運行的實際上就是Main和returnThreadInfo兩個線程,那
麼這兩個線程就會競爭CPU,誰先搶到CPU的控制權,誰就會先運行(實際上線程誰能優先搶到CPU運行時間是靠優先級來決定的,優先級可以通
過線程的setPriority(int newPriority)來設置,newPriority的取值是1-10,newPriority值越大,線程的優先級就越高,優先強佔CPU的機率
就越大。線程默認的優先級是5)。由於Main和returnThreadInfo的優先級都默認爲5,所以它們爭搶CPU的機率是相同的。又因爲Main線程實際
上是比returnThreadInfo線程先啓動的,所以在這個程序中,Main的System.out.println(returnThreadInfo.getThreadInfo())反而比
returnThreadInfo的run方法更早運行,所以輸出的str值還是初始的"Hello"。
2、誤區二:認爲線程運行完畢後,線程消亡的同時,線程對象也會一併被回收。
   下面對ReturnThreadInfo類的源代碼進行修改,將ReturnThreadInfo線程的優先級設置爲10:
    public ReturnThreadInfo() {
        this.str = "Hello";
this.setPriority(10);
    }
   這樣returnThreadInfo線程的run()方法就會在Main類的System.out.println(returnThreadInfo.getThreadInfo())語句之前被運行。因此
有很多人會認爲當returnThreadInfo線程的run()方法運行完畢並返回後,線程就會死亡,那麼Main類的最後一句System.out.println
(returnThreadInfo.getThreadInfo())就會出問題,等於調用了已經不存在的對象:returnThreadInfo。
   實際上這存在着很大的一個誤區,線程的死亡並不意味着線程對象的銷燬和回收。線程的死亡指的是當線程的run方法結束後,該線程就無
法被重用和啓動,但它的對象還存在並且它的屬性和方法還一樣可以被使用,因此System.out.println(returnThreadInfo.getThreadInfo())
輸出的並不是NULL而是"Hello World!",只有當整個應用程序都結束後,returnThreadInfo對象纔會被銷燬和回收。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章