天天看點

初入java多線程

1.程序與線程

    程序(Process)是計算機中的程式關于某資料集合上的一次運作活動,是系統進行資源配置設定和排程的基本機關,是作業系統結構的基礎。在程式設計中,程序是程式的運作的執行個體,而運作一個java程式實質是運作一個java虛拟機程序(JVM),也就是說運作的java程式就是一個java虛拟機程序.

    線程則是程序中可獨立執行的最小機關,是CPU排程和分派的基本機關。一個程序可以包含多個線程,這些線程共享程序中的資源,如記憶體空間,句柄檔案等。為了充分的利用CPU資源,一般都會使用多線程進行處理提高任務的平均執行速度,這是我們多線程程式設計的初衷。

2.線程的生命周期

初入java多線程

(1)建立狀态:線程被建立并沒有被啟動的狀态。建立線程的方式有三種:第一種是繼承Thread類,重寫run方法,第二種是實作Runnable接口,實作run方法,第三種是實作Callable接口,實作call方法。第一種方法因為是使用繼承來實作是以針對java程式設計來說不夠靈活,第二種和第三種面向接口程式設計則更靈活,并且對外暴露的細節較少,讓開發人員更專注于接口方法的實作上。第三種我們通過接口對比會發現,這種實作可以通過call方法擷取線程體的運作結果。

(2)就緒狀态:線程在建立完成後在啟動之後但是并沒有被運作的狀态。處于就緒狀态的線程,隻是說明此線程已經做好了準備,随時等待CPU排程執行,并不是說此線程啟動後立即就會執行。在java中,我們調用start()方法之後但是run()方法還沒有被執行則該線程處理就緒狀态,并且我們不能多次調用start()方法否則會報IllegalStateException異常。

(3)運作狀态:當CPU開始排程處于就緒狀态的線程時,此時線程才得以真正執行,即進入到運作狀态,即執行 run()方法之後。其中緒狀态是進入到運作狀态的唯一入口,也就是說,線程要想進入運作狀态執行,首先必須處于就緒狀态中;處于運作狀态的線程最為複雜,它可以變為阻塞狀态、就緒狀态和死亡狀态。

(4)阻塞狀态:當處于運作狀态中的線程由于某種原因,暫時放棄對CPU的使用權停止執行,此時進入阻塞狀态,直到其再次進入到就緒狀态,才 有機會再次被CPU調用以進入到運作狀态。

(5)死亡狀态:線程執行完了或者因異常退出了run()方法,該線程結束生命周期。

3.java中線程的建立

   在java平台中建立一個線程就是建立一個Thread類或者其子類的一個執行個體。每個線程都有它要執行的任務,而處理邏輯可以在Thread類的run執行個體方法中直接實作或者通過該方法進行調用,應此run方法相當于線程任務處理邏輯的入口方法,它是java虛拟機在運作相應線程時直接調用而不是由應用代碼進行調用。

public class CreateThread {
   public static void main(String[] args) {
       HelloThread t1 = new HelloThread();
       Thread t2 = new Thread(new HelloRunnable());
       t1.start();// 啟動線程1
       t2.start();// 啟動線程2
   }

   /**
    * 通過繼承Thread來建立線程
    */
   public static class HelloThread extends Thread{
       @Override
       public void run() {
           try{
               Thread.sleep(1000);
               System.out.println("hello,this is a thread#1");
           }catch (Exception e){
               e.printStackTrace();
           }

       }
   }

   /**
    * 通過實作Runnable來建立線程
    */
  public static  class  HelloRunnable implements Runnable{
       public void run() {
           try{
               Thread.sleep(500);
               System.out.println("hello,this is a thread#2");
           }catch (Exception e){
               e.printStackTrace();
           }
       }
   }
}           

運作結果:

hello,this is a thread#2
hello,this is a thread#1

Process finished with exit code 0            

   運作一個線程實際上就是讓java虛拟機執行線程類的run方法,進而執行相應線程的任務處理邏輯。是以我們通過Thread的start()方法來啟動相應的線程,其實質上是向java虛拟機發送一個運作相應線程的請求,然後java虛拟機調用相應線程的run()方法,在這裡要說明的是線程的具體執行時間是由線程排程器決定的。不管采用哪種方法建立線程,一旦該線程的run() 方法執行結束,相應的線程運作也就結束了,其占用的資源也被java虛拟機回收。

4.線程的屬性

   java線程的屬性主要包括線程編号(ID),線程名稱(Name), 線程類别(Daemon)和優先級(Priority)。

   線程編号(ID):用于辨別不同的線程,不同的線程擁有不通的程式設計,需要注意的是某個編号的線程運作結束後,該編号可能被後續建立的線程再使用,不同線程擁有不同的編号即唯一性隻在java虛拟機的一次運作有效,重新開機java虛拟機之後則線程編号可能與上一次啟動的java虛拟機上的線程編号相同;

   線程名稱(Name):用于區分不同的線程,但是java不禁止為不同的線程設定項目的線程名稱。線程名稱(Name)的預設值與線程編号有關,預設格式“thread-線程編号”,在多線程程式設計中設定線程名稱有助于代碼調試和問題定位。

   線程類别(Daemon):值為ture或者false,值為true表示相應的線程是守護線程,否則表示相應的線程是使用者線程,該屬性的預設值和其父線程的值相同。線程類别的值必須線上程啟動之前設定,啟動之後再設定會抛出IllegalThreadStateException異常,并且在一些關鍵任務處理的線程不适宜設定為守護線程。

   線程優先級(Priority):表示應用程式優先執行那個線程,一般使用預設的優先級即可,其取值範圍是 1(Thread.MIN_PRIORITY ) - 10 (Thread.MAX_PRIORITY ),預設情況下,每一個線程都會配置設定一個優先級 NORM_PRIORITY(5);不恰當的設定線程優先級會出現線程饑餓的非常嚴重的問題。

/**
* 列印線程屬性
*/
public class ThreadProperty {
   public static void main(String[] args) {
       long id = Thread.currentThread().getId();
       String name = Thread.currentThread().getName();
       boolean daemon = Thread.currentThread().isDaemon();
       int priority = Thread.currentThread().getPriority();
       System.out.println("線程ID:"+id);
       System.out.println("線程名稱:"+name);
       System.out.println("線程類别:"+daemon);
       System.out.println("線程優先級:"+priority);
   }
}            
線程ID:1
線程名稱:main
線程類别:false
線程優先級:5           

繼續閱讀