6.1 線程簡介
隨著計算機的飛速發(fā)展,個人計算機上的操作系統(tǒng)也紛紛采用多任務(wù)和分時設(shè)計,將早期只有大型計算機才具有的系統(tǒng)特性帶到了個人計算機系統(tǒng)中。一般可以在同一時間內(nèi)執(zhí)行多個程序的操作系統(tǒng)都有進程的概念。一個進程就是一個執(zhí)行中的程序,而每一個進程都有自己獨立的一塊內(nèi)存空間、一組系統(tǒng)資源。在進程概念中,每一個進程的內(nèi)部數(shù)據(jù)和狀態(tài)都是完全獨立的。Java程序通過流控制來執(zhí)行程序流,程序中單個順序的流控制稱為線程,多線程則指的是在單個程序中可以同時運行多個不同的線程,執(zhí)行不同的任務(wù)。多線程意味著一個程序的多行語句可以看上去幾乎在同一時間內(nèi)同時運行。
線程與進程相似,是一段完成某個特定功能的代碼,是程序中單個順序的流控制;但與進程不同的是,同類的多個線程是共享一塊內(nèi)存空間和一組系統(tǒng)資源,而線程本身的數(shù)據(jù)通常只有微處理器的寄存器數(shù)據(jù),以及一個供程序執(zhí)行時使用的堆棧。所以系統(tǒng)在產(chǎn)生一個線程,或者在各個線程之間切換時,負擔(dān)要比進程小的多,正因如此,線程被稱為輕負荷進程(light-weight process)。一個進程中可以包含多個線程。
一個線程是一個程序內(nèi)部的順序控制流。 來源:www.examda.com
1. 進程:每個進程都有獨立的代碼和數(shù)據(jù)空間(進程上下文) ,進程切換的開銷大。
2. 線程:輕量的進程,同一類線程共享代碼和數(shù)據(jù)空間,每個線程有獨立的運行棧和程序計數(shù)器(PC),線程切換的開銷小。
3. 多進程:在操作系統(tǒng)中,能同時運行多個任務(wù)程序。
4. 多線程:在同一應(yīng)用程序中,有多個順序流同時執(zhí)行。
6.1.1 線程的概念模型
Java內(nèi)在支持多線程,它的所有類都是在多線程下定義的,Java利用多線程使整個系統(tǒng)成為異步系統(tǒng)。Java中的線程由三部分組成,如圖6.1所示。
1. 虛擬的CPU,封裝在java.lang.Thread類中。
2. CPU所執(zhí)行的代碼,傳遞給Thread類。
3. CPU所處理的數(shù)據(jù),傳遞給Thread類。
6. 1. 2 線程體(1)
Java的線程是通過java.lang.Thread類來實現(xiàn)的。當我們生成一個Thread類的對象之后,一個新的線程就產(chǎn)生了。
此線程實例表示Java解釋器中的真正的線程,通過它可以啟動線程、終止線程、線程掛起等,每個線程都是通過類Thread在Java的軟件包Java.lang中定義,它的構(gòu)造方法為:
public Thread (ThreadGroup group,Runnable target,String name)??;
其中,group 指明該線程所屬的線程組;target實際執(zhí)行線程體的目標對象,它必須實現(xiàn)接口Runnable; name為線程名。Java中的每個線程都有自己的名稱,Java提供了不同Thread類構(gòu)造器,允許給線程指定名稱。如果name為null時,則Java自動提供的名稱。
當上述構(gòu)造方法的某個參數(shù)為null時,我們可得到下面的幾個構(gòu)造方法:
public Thread ();
public Thread (Runnable target);
public Thread (Runnable target,String name);
public Thread (String name);
public Thread (ThreadGroup group,Runnable target);
public Thread (ThreadGroup group,String name);
一個類聲明實現(xiàn)Runnable接口就可以充當線程體,在接口Runnable中只定義了一個方法 run():
public void run();
任何實現(xiàn)接口Runnable的對象都可以作為一個線程的目標對象,類Thread本身也實現(xiàn)了接口Runnable,因此我們可以通過兩種方法實現(xiàn)線程體。
(一)定義一個線程類,它繼承線程類Thread并重寫其中的方法 run(),這時在初始化這個類的實例時,目標target可為null,表示由這個實例對來執(zhí)行線程體。由于Java只支持單重繼承,用這種方法定義的類不能再繼承其它父類。
(二)提供一個實現(xiàn)接口Runnable的類作為一個線程的目標對象,在初始化一個Thread類或者Thread子類的線程對象時,把目標對象傳遞給這個線程實例,由該目標對象提供線程體 run()。這時,實現(xiàn)接口Runnable的類仍然可以繼承其它父類。
每個線程都是通過某個特定Thread對象的方法run( )來完成其操作的,方法run( )稱為線程體。圖6.2表示了java線程的不同狀態(tài)以及狀態(tài)之間轉(zhuǎn)換所調(diào)用的方法。
1. 創(chuàng)建狀態(tài)(new Thread)
執(zhí)行下列語句時,線程就處于創(chuàng)建狀態(tài):
Thread myThread = new MyThreadClass( );
當一個線程處于創(chuàng)建狀態(tài)時,它僅僅是一個空的線程對象,系統(tǒng)不為它分配資源。
2. 可運行狀態(tài)( Runnable )
Thread myThread = new MyThreadClass( );
myThread.start( );
當一個線程處于可運行狀態(tài)時,系統(tǒng)為這個線程分配了它需的系統(tǒng)資源,安排其運行并調(diào)用線程運行方法,這樣就使得該線程處于可運行( Runnable )狀態(tài)。需要注意的是這一狀態(tài)并不是運行中狀態(tài)(Running ),因為線程也許實際上并未真正運行。由于很多計算機都是單處理器的,所以要在同一時刻運行所有的處于可運行狀態(tài)的線程是不可能的,Java的運行系統(tǒng)必須實現(xiàn)調(diào)度來保證這些線程共享處理器。
隨著計算機的飛速發(fā)展,個人計算機上的操作系統(tǒng)也紛紛采用多任務(wù)和分時設(shè)計,將早期只有大型計算機才具有的系統(tǒng)特性帶到了個人計算機系統(tǒng)中。一般可以在同一時間內(nèi)執(zhí)行多個程序的操作系統(tǒng)都有進程的概念。一個進程就是一個執(zhí)行中的程序,而每一個進程都有自己獨立的一塊內(nèi)存空間、一組系統(tǒng)資源。在進程概念中,每一個進程的內(nèi)部數(shù)據(jù)和狀態(tài)都是完全獨立的。Java程序通過流控制來執(zhí)行程序流,程序中單個順序的流控制稱為線程,多線程則指的是在單個程序中可以同時運行多個不同的線程,執(zhí)行不同的任務(wù)。多線程意味著一個程序的多行語句可以看上去幾乎在同一時間內(nèi)同時運行。
線程與進程相似,是一段完成某個特定功能的代碼,是程序中單個順序的流控制;但與進程不同的是,同類的多個線程是共享一塊內(nèi)存空間和一組系統(tǒng)資源,而線程本身的數(shù)據(jù)通常只有微處理器的寄存器數(shù)據(jù),以及一個供程序執(zhí)行時使用的堆棧。所以系統(tǒng)在產(chǎn)生一個線程,或者在各個線程之間切換時,負擔(dān)要比進程小的多,正因如此,線程被稱為輕負荷進程(light-weight process)。一個進程中可以包含多個線程。
一個線程是一個程序內(nèi)部的順序控制流。 來源:www.examda.com
1. 進程:每個進程都有獨立的代碼和數(shù)據(jù)空間(進程上下文) ,進程切換的開銷大。
2. 線程:輕量的進程,同一類線程共享代碼和數(shù)據(jù)空間,每個線程有獨立的運行棧和程序計數(shù)器(PC),線程切換的開銷小。
3. 多進程:在操作系統(tǒng)中,能同時運行多個任務(wù)程序。
4. 多線程:在同一應(yīng)用程序中,有多個順序流同時執(zhí)行。
6.1.1 線程的概念模型
Java內(nèi)在支持多線程,它的所有類都是在多線程下定義的,Java利用多線程使整個系統(tǒng)成為異步系統(tǒng)。Java中的線程由三部分組成,如圖6.1所示。
1. 虛擬的CPU,封裝在java.lang.Thread類中。
2. CPU所執(zhí)行的代碼,傳遞給Thread類。
3. CPU所處理的數(shù)據(jù),傳遞給Thread類。
6. 1. 2 線程體(1)
Java的線程是通過java.lang.Thread類來實現(xiàn)的。當我們生成一個Thread類的對象之后,一個新的線程就產(chǎn)生了。
此線程實例表示Java解釋器中的真正的線程,通過它可以啟動線程、終止線程、線程掛起等,每個線程都是通過類Thread在Java的軟件包Java.lang中定義,它的構(gòu)造方法為:
public Thread (ThreadGroup group,Runnable target,String name)??;
其中,group 指明該線程所屬的線程組;target實際執(zhí)行線程體的目標對象,它必須實現(xiàn)接口Runnable; name為線程名。Java中的每個線程都有自己的名稱,Java提供了不同Thread類構(gòu)造器,允許給線程指定名稱。如果name為null時,則Java自動提供的名稱。
當上述構(gòu)造方法的某個參數(shù)為null時,我們可得到下面的幾個構(gòu)造方法:
public Thread ();
public Thread (Runnable target);
public Thread (Runnable target,String name);
public Thread (String name);
public Thread (ThreadGroup group,Runnable target);
public Thread (ThreadGroup group,String name);
一個類聲明實現(xiàn)Runnable接口就可以充當線程體,在接口Runnable中只定義了一個方法 run():
public void run();
任何實現(xiàn)接口Runnable的對象都可以作為一個線程的目標對象,類Thread本身也實現(xiàn)了接口Runnable,因此我們可以通過兩種方法實現(xiàn)線程體。
(一)定義一個線程類,它繼承線程類Thread并重寫其中的方法 run(),這時在初始化這個類的實例時,目標target可為null,表示由這個實例對來執(zhí)行線程體。由于Java只支持單重繼承,用這種方法定義的類不能再繼承其它父類。
(二)提供一個實現(xiàn)接口Runnable的類作為一個線程的目標對象,在初始化一個Thread類或者Thread子類的線程對象時,把目標對象傳遞給這個線程實例,由該目標對象提供線程體 run()。這時,實現(xiàn)接口Runnable的類仍然可以繼承其它父類。
每個線程都是通過某個特定Thread對象的方法run( )來完成其操作的,方法run( )稱為線程體。圖6.2表示了java線程的不同狀態(tài)以及狀態(tài)之間轉(zhuǎn)換所調(diào)用的方法。
1. 創(chuàng)建狀態(tài)(new Thread)
執(zhí)行下列語句時,線程就處于創(chuàng)建狀態(tài):
Thread myThread = new MyThreadClass( );
當一個線程處于創(chuàng)建狀態(tài)時,它僅僅是一個空的線程對象,系統(tǒng)不為它分配資源。
2. 可運行狀態(tài)( Runnable )
Thread myThread = new MyThreadClass( );
myThread.start( );
當一個線程處于可運行狀態(tài)時,系統(tǒng)為這個線程分配了它需的系統(tǒng)資源,安排其運行并調(diào)用線程運行方法,這樣就使得該線程處于可運行( Runnable )狀態(tài)。需要注意的是這一狀態(tài)并不是運行中狀態(tài)(Running ),因為線程也許實際上并未真正運行。由于很多計算機都是單處理器的,所以要在同一時刻運行所有的處于可運行狀態(tài)的線程是不可能的,Java的運行系統(tǒng)必須實現(xiàn)調(diào)度來保證這些線程共享處理器。