回健永
(天津機電職業(yè)技術(shù)學院,天津市 300131)
基于Java語言的多線程機制的實現(xiàn)
回健永
(天津機電職業(yè)技術(shù)學院,天津市 300131)
Java語言是目前使用最為廣泛的網(wǎng)絡編程語言之一。文章首先分析了多線程的機制及其特性,然后通過實例來研究如何用創(chuàng)建 Thread類的子類和實現(xiàn)Runnable接口兩種不同方法實現(xiàn)多線程的編程。
Java;多線程;Thread類;Runnable接口
Java是少數(shù)的幾種支持“多線程”的語言之一,它的一個重要功能特點就是內(nèi)置對多線程的支持。
多線程指的是在單個進程中可以同時運行多個不同的線程,執(zhí)行不同的任務。使用多線程技術(shù),可以使編程人員很方便地開發(fā)出能同時處理多個任務的功能強大的應用程序。多線程的程序能更好地表述和解決現(xiàn)實世界的具體實際問題,是計算機應用開發(fā)和程序設計的一個必然發(fā)展趨勢。
1.線程(thread)的定義
線程是指進程中單一順序的控制流,又稱為輕量級進程。要說清楚這個概念,要與進程結(jié)合起來分析。線程是比進程更小的執(zhí)行單位。一個進程在其執(zhí)行過程中,可以產(chǎn)生多個線程,形成多條執(zhí)行點,每條執(zhí)行點即每個線程。線程有它自身的產(chǎn)生、存在和消亡的過程,它是一個動態(tài)的概念。線程很像進程,它們在概念上是相關(guān)的。它們都是代表著程序當前的運行情況,都是執(zhí)行一定的任務,而且它們都是可以并行并發(fā)執(zhí)行的。
2.線程的狀態(tài)與生命周期
每個Java程序都有一個默認的主線程,對于Java的應用程序,主線程是main()方法執(zhí)行的線索;對于App let程序,主線程是指揮瀏覽器加載并執(zhí)行Java App let程序的線索。要想實現(xiàn)多線程,必須在主線程中創(chuàng)建新的線程對象。任何一個線程,在它的一個完整生命周期中通常具有創(chuàng)建、就緒、運行、阻塞和終止五種狀態(tài)。在給定的時間點上,一個線程只能處于一種狀態(tài)。圖1顯示了一個Java線程在它的生命周期中的各個狀態(tài)。
圖1 線程的生命周期
3.線程的調(diào)度及優(yōu)先級
每個線程都有一個優(yōu)先級,它在線程被創(chuàng)建時其優(yōu)先級是由創(chuàng)建它的線程所決定的;也可以在線程創(chuàng)建之后的任意時刻通過調(diào)用setPriority的方法來修改線程的優(yōu)先級。線程的優(yōu)先級是在M IN_PRIORITY和MA X_PRlORITY范圍內(nèi)的一個整數(shù)值,數(shù)值越大,代表線程的優(yōu)先級越高。
當一個線程進入運行狀態(tài)之后,這個線程就稱為是被“調(diào)度”或被線程調(diào)度管理器選中了。在Ja2 va系統(tǒng)中,線程調(diào)度依據(jù)優(yōu)先級基礎上的“先到先服務”原則。在任意時刻,當有多個線程處于可運行狀態(tài),運行系統(tǒng)總是挑選一個優(yōu)先級最高的線程執(zhí)行,只有當線程停止、退出或者由于某種原因不執(zhí)行的時候,低優(yōu)先級的線程才可以被執(zhí)行。如果當高優(yōu)先級的線程處于阻塞狀態(tài),并且CPU處于空閑時,低優(yōu)先級的線程會被調(diào)度執(zhí)行;另外若有兩個相同優(yōu)先級的線程同時等待執(zhí)行時,運行系統(tǒng)會以round-robin的方式選擇一個執(zhí)行。
在Java中,實現(xiàn)多線程的應用有兩種方式:一種是繼承 Thread類來創(chuàng)建對象用戶,另一種是聲明實現(xiàn)了Runnable接口的類。兩種方式都需要使用到Java基礎類庫中的Thread類及其方法。
1.通過繼承 Thread類實現(xiàn)多線程
用Thread類實現(xiàn)多線程,用戶需要在程序中創(chuàng)建自己的 Thread類的子類和重新定義一個自己的run()方法,這個run()方法中包含了用戶線程的操作。run()方法是定義在 Thread類里的一個方法,因此把線程的程序代碼編寫在run()方法內(nèi),事實上所做的就是覆寫的操作。這樣在程序需要建立線程時,它只需要創(chuàng)建一個已定義好的Thread類的子類的實例就可以了。用Thread類實現(xiàn)多線程定義的語法如下:
class類名稱extends Thread //從 Thread類擴展出子類
{
屬性……
方法……
修飾符 run(){ //覆寫 Thread類里的run()方法
以線程處理的程序;}
}
用此方法,在一個Java App lication程序中定義兩個類,一個是程序的主類 TestThread,另一個是用戶自定義的 Thread類的子類p rimeThread。程序的主線程,即 TestThread主類的main()方法首先根據(jù)用戶輸入的命令行參數(shù)創(chuàng)建一個p rimeThread類的對象,并調(diào)用start()方法啟動這個子線程對象,使之進入就緒狀態(tài)。主線程首先輸出一行信息表示自己在活動,然后調(diào)用sleep()方法使自己休眠一段時間以便子線程獲取處理器,進入運行狀態(tài)的子線程將檢查一個數(shù)值是否是素數(shù)并顯示出來,然后也休眠一段時間以便父線程獲得處理器。獲得處理器的父線程將顯示一行信息表示自己在活動,然后再休眠……每次子線程啟動都檢查一個新的增大一個的數(shù)值是否為素數(shù)并打印,直至該數(shù)大于其預定的上限。此時子線程從run()方法返回并結(jié)束其運行,然后主線程也結(jié)束。
2.通過實現(xiàn)Runnable接口實現(xiàn)多線程
用創(chuàng)建Thread子類的方法雖然簡便易用,但是要求必須有一個以 Thread為父類的用戶子類。假設用戶子類需要有另一個父類,則根據(jù)Java程序只允許單一繼承的原則,就不能用 Thread類產(chǎn)生線程了,因為Java不允許多繼承,這時我們可以考慮使用Runnable接口的方法來創(chuàng)建線程。其定義的語法如下:
class類名稱 imp lem ents Runnable //實現(xiàn)Runnable接口
{
屬性……
方法……
修飾符 run(){ //覆寫 Thread類里的run()方法
以線程處理的程序;}
}
Runnable接口只有一個方法run(),實現(xiàn)這個接口就必須要定義run()方法的具體內(nèi)容,用戶新建線程的操作也由這個方法來決定。Runnable接口中的這個run()方法是一個較特殊的方法,它可以被運行系統(tǒng)自動識別和執(zhí)行。定義好run()方法之后,當用戶程序需要建立新線程時,只要以這個實現(xiàn)了run()方法的類為參數(shù)創(chuàng)建系統(tǒng)類Thread的對象,就可以把用戶實現(xiàn)的run()方法繼承過來。所以,一個實現(xiàn)了Runnable接口的類實際上定義了一個主線程之外的新線程的操作,而定義新線程的操作和執(zhí)行流程,是實現(xiàn)多線程應用的最主要工作之一。
3.兩種實現(xiàn)機制的比較
不管實現(xiàn)了Runnable接口還是繼承了 Thread類,兩種多線程機制運行的結(jié)果都是一樣的。經(jīng)分析可見,實現(xiàn)Runnable接口相對于繼承Thread類來說,有如下三個顯著優(yōu)勢。
(1)適合多個相同程序代碼的線程去處理同一資源的情況,把虛擬CPU(線程)同程序的代碼、數(shù)據(jù)有效分離,較好地體現(xiàn)了面向?qū)ο蟮脑O計思想。
(2)可以避免由于Java的單繼承特性帶來的局限。
(3)增強了程序的健壯性,代碼能夠被多個線程共享,代碼與數(shù)據(jù)是獨立的。當多個線程的執(zhí)行代碼來自同一個類的實例時,即稱它們共享相同的代碼。
由于 Thread類實現(xiàn)了Runnable接口,也就是說 Thread類也是Runnable接口的一個子類。在實際的開發(fā)中,幾乎所有多線程的應用都可以使用實現(xiàn)Runnable接口。
4.多線程實現(xiàn)應用實例
在程序中,多線程的實現(xiàn)可以通過創(chuàng)建 Thread類的子類和通過實現(xiàn)Runnable接口兩個途徑來完成。無論采用哪種途徑,程序員在編程中可以用定義用戶線程的run()方法與建立用戶線程實例來控制兩個關(guān)鍵性操作。用實現(xiàn)Runnable接口的方法實現(xiàn)多線程程序如下:
import java.app let.App let;
import java.aw t.3;
public class TestRunnable extends App let imp lem ents Runnable//Java App let主類
{
Label p romp t1=new Label(“第一個子線程”);
Label p romp t2=new Label(“第二個子線程”);
TextField threadFirst=new TextField(14);
TextField threadSecond=new TextField(14);
Thread threadl,thread2;
int countl=O,count2=0;
public void init()
{
add(p romp t1);
add(threadFirst);
add(p romp t2);
add(threadSecond);}
public void start()
{
thread1=new Thread(this,“FirstThread”);
thread2=new Thread(this,“Second Thread”);
thread1.start();//啟動線程對象,進入就緒狀態(tài)
thread2.start();}
public void run()//實現(xiàn)Runnable接口的run()方法,在該線程啟動時自動執(zhí)行
{
String currentRunning;
w hile(true)
{
try
{//使當前活動線程休眠0到3秒
Thread.sleep((int)(M ath.random()3 30000));}
catch(Interrup ted Excep tion e){}
currentRunning=Thread.currentThread().getName();
if(currentRunning.equals(“FirstThread”))
{countl++;
threadFirst.setText(“線程 1”第 +countl+“次被調(diào)度”);}
else if(currentRunning.equals(“Second Thread”)){
count2+ +;
threadSecond.setText(“線程2第”+count2+”次被調(diào)度”);}
}}}
這是一個Java App let,所以程序的主類 TestRunnable必須是App let類的子類;同時它還實現(xiàn)了Runnable接口并具體實現(xiàn)了run()方法。在TestRunnable中創(chuàng)建了兩個子線程,都是Thread類的對象。這兩個對象的構(gòu)造函數(shù)指明它們將繼承當前類中的run()方法,即它們被調(diào)度時將執(zhí)行這個run()方法。這個run()方法將首先休眠一段隨機的時間,然后統(tǒng)計當前活動(即獲得了處理器的)線程被調(diào)度次數(shù)并顯示在相應的文本框中。
[1]李相國等.Java實例精通[M].北京:機械工業(yè)出版社,2009.
[2]印旻.Java語言與面向?qū)ο蟪绦蛟O計[M].北京:清華大學出版社,2002.
[3]袁加全.基于Java多線程的有限元并行計算的研究[D].天津:天津工業(yè)大學,2005.
The Imp lem entation of M ulti-Th read M echanism Based on Java L anguage
HU IJian-yong
(Tianjin Vocational College of M echanics and Electricity,Tianjin 300131 China)
Java language is one of the most popular p rogramm ing languages,w hich has the fea2 tures of being simp le,transportable,flexible and multi-threaded.This article first makes analyses on the mechanism and characteristics of m ulti-thread system and then makes some researches on how to build the subtypes of the Thread and how to imp lement them ulti-thread p rogramm ing by using Runna2 ble interface.
Java;multi-thread system;Thread;Runnable interface
TP311
A
1673-582X(2011)08-0058-04
2011-05-30
回健永(1974-),男,天津市人,大學本科學歷,天津機電職業(yè)技術(shù)學院講師,主要研究方向為計算機應用技術(shù)、軟件工程。