Java Thread

線程是一個程序的多個執行路徑,執行調度的單位,依託於進程存在。 線程不只能夠共享進程的內存,並且還擁有一個屬於本身的內存空間,這段內存空間也叫作線程棧,是在創建線程時由系統分配的,主要用來保存線程內部所使用的數據,如線程執行函數中所定義的變量。java

注意:Java中的多線程是一種搶佔機制而不是分時機制。搶佔機制指的是有多個線程處於可運行狀態,可是隻容許一個線程在運行,他們經過競爭的方式搶佔CPU。多線程

線程的定義(Defining)ide

定義一個線程(Defining a Thread)有兩種方法函數

  1) 繼承java.lang.Thread類spa

/**
 * 使用繼承java.lang.Thread類的方式建立一個線程
 * 
 * @author DreamSea 2011-12-29 20:17:06
 */
public class ThreadTest extends Thread {

    /**
     * 重寫(Override)run()方法 JVM會自動調用該方法
     */
    public void run() {
        System.out.println("I'm running!");
    }
}

  注意:重寫(override)run()方法在該線程的start()方法被調用後,JVM會自動調用run方法來執行任務;可是重載 (overload)run()方法,該方法和普通的成員方法同樣,並不會因調用該線程的start()方法而被JVM自動運行。 例如:線程

public class ThreadTest extends Thread {

    /**
     * 重寫(Override)run()方法 JVM會自動調用該方法
     */
    @Override
    public void run() {
        System.out.println("I'm running!");
    }

    /**
     * 重載(Overload)run()方法 和普通的方法同樣,並不會在該線程的start()方法被調用後被JVM自動運行
     */
    public void run(int times) {
        System.out.println("I'm running!(Overload)");
    }
}

不建議使用此方法定義線程,由於採用繼承Thread的方式定義線程後,你不能在繼承其餘的類了,致使程序的可擴展性大大下降。code

  2) 實現java.lang.Runnable接口對象

/**
 * 經過實現Runnable接口建立一個線程
 * @author DreamSea
 */
public class ThreadTest implements Runnable {
    public void run() {
            System.out.println("I'm running!");
    }
}

線程的啓動(Starting)
繼承

任何一個線程的執行的前提都是必須有Thread class的實例存在,而且經過調用start()方法啓動線程。接口

 1)若是線程是繼承Thread類,則建立方式以下:

ThreadTest1 tt = new ThreadTest1();
tt.start();

2)若是是實現Runnable接口,則建立方式以下:

ThreadTest2 tt = new ThreadTest2();
Thread t = new Thread(tt);
t.start();

線程的狀態(State)

  新生狀態(New): 當一個線程的實例被建立即便用new關鍵字和Thread類或其子類建立一個線程對象後,此時該線程處於新生(new)狀態,處於新生狀態的線程有本身的內存空間,但該線程並無運行,此時線程還不是活着的(not  alive);

  就緒狀態(Runnable): 通 過調用線程實例的start()方法來啓動線程使線程進入就緒狀態(runnable);處於就緒狀態的線程已經具有了運行條件,但尚未被分配到CPU 即不必定會被當即執行,此時處於線程就緒隊列,等待系統爲其分配CPU,等待狀態並非執行狀態; 此時線程是活着的(alive);

  運行狀態(Running): 一 旦獲取CPU(被JVM選中),線程就進入運行(running)狀態,線程的run()方法纔開始被執行;在運行狀態的線程執行本身的run()方法中 的操做,直到調用其餘的方法而終止、或者等待某種資源而阻塞、或者完成任務而死亡;若是在給定的時間片內沒有執行結束,就會被系統給換下來回到線程的等待 狀態;此時線程是活着的(alive);

  阻塞狀態(Blocked):經過調用join()、sleep()、wait()或者資源被暫用使線程處於阻塞(blocked)狀態;處於Blocking狀態的線程仍然是活着的(alive)

     死亡狀態(Dead):當 一個線程的run()方法運行完畢或被中斷或被異常退出,該線程到達死亡(dead)狀態。此時可能仍然存在一個該Thread的實例對象,當該 Thready已經不可能在被做爲一個可被獨立執行的線程對待了,線程的獨立的call stack已經被dissolved。一旦某一線程進入Dead狀態,他就不再能進入一個獨立線程的生命週期了。對於一個處於Dead狀態的線程調用 start()方法,會出現一個運行期(runtime exception)的異常;處於Dead狀態的線程不是活着的(not  alive)。

線程狀態圖

線程的方法(Method)、屬性(Property)

    1)優先級(priority)

每一個類都有本身的優先級,通常property用1-10的整數表示,默認優先級是5,優先級最高是10;優先級高的線程並不必定比優先級低的線程執行的機會高,只是執行的機率高;默認一個線程的優先級和建立他的線程優先級相同;

    2)Thread.sleep()/sleep(long millis)

當前線程睡眠 /millis的時間(millis指定睡眠時間是其最小的不執行時間,由於sleep(millis)休眠到達後,沒法保證會被JVM當即調 度);sleep()是一個靜態方法(static method) ,因此他不會中止其餘的線程也處於休眠狀態;線程sleep()時不會失去擁有的對象鎖。 做用:保持對象鎖,讓出CPU,調用目的是不讓當前線程獨自霸佔該進程所獲取的CPU資源,以留必定的時間給其餘線程執行的機會;

    3)Thread.yield()

  讓出CPU的使用權,給其餘線程執行機會、讓同等優先權的線程運行(但並不保證當前線程會被JVM再次調度、使該線程從新進入Running狀態),若是沒有同等優先權的線程,那麼yield()方法將不會起做用。

    4)thread.join()

 使用該方法的線程會在此之間執行完畢後再往下繼續執行。

    5)object.wait()

  當一個線程執 行到wait()方法時,他就進入到一個和該對象相關的等待池(Waiting Pool)中,同時失去了對象的機鎖—暫時的,wait後還要返還對象鎖。當前線程必須擁有當前對象的鎖,若是當前線程不是此鎖的擁有者,會拋出 IllegalMonitorStateException異常,因此wait()必須在synchronized block中調用。

    6)object.notify()/notifyAll()

  喚醒在當前對象等待池中等待的第一個線程/全部線程。notify()/notifyAll()也必須擁有相同對象鎖,不然也會拋出IllegalMonitorStateException異常。

    7)Synchronizing Block

 Synchronized Block/方法控制對類成員變量的訪問;Java中的每個對象都有惟一的一個內置的鎖,每一個Synchronized Block/方法只有持有調用該方法被鎖定對象的鎖才能夠訪問,不然所屬線程阻塞;機鎖具備獨佔性、一旦被一個Thread持有,其餘的Thread就不能再擁有(不能訪問其餘同步方法),方法一旦執行,就獨佔該鎖,直到從該方法返回時纔將鎖釋放,此後被阻塞的線程方能得到該鎖,從新進入可執行狀態。

相關文章
相關標籤/搜索