回健永
(天津機(jī)電職業(yè)技術(shù)學(xué)院,天津市 300131)
基于Java語言的多線程機(jī)制的實(shí)現(xiàn)
回健永
(天津機(jī)電職業(yè)技術(shù)學(xué)院,天津市 300131)
Java語言是目前使用最為廣泛的網(wǎng)絡(luò)編程語言之一。文章首先分析了多線程的機(jī)制及其特性,然后通過實(shí)例來研究如何用創(chuàng)建 Thread類的子類和實(shí)現(xiàn)Runnable接口兩種不同方法實(shí)現(xiàn)多線程的編程。
Java;多線程;Thread類;Runnable接口
Java是少數(shù)的幾種支持“多線程”的語言之一,它的一個(gè)重要功能特點(diǎn)就是內(nèi)置對(duì)多線程的支持。
多線程指的是在單個(gè)進(jìn)程中可以同時(shí)運(yùn)行多個(gè)不同的線程,執(zhí)行不同的任務(wù)。使用多線程技術(shù),可以使編程人員很方便地開發(fā)出能同時(shí)處理多個(gè)任務(wù)的功能強(qiáng)大的應(yīng)用程序。多線程的程序能更好地表述和解決現(xiàn)實(shí)世界的具體實(shí)際問題,是計(jì)算機(jī)應(yīng)用開發(fā)和程序設(shè)計(jì)的一個(gè)必然發(fā)展趨勢(shì)。
1.線程(thread)的定義
線程是指進(jìn)程中單一順序的控制流,又稱為輕量級(jí)進(jìn)程。要說清楚這個(gè)概念,要與進(jìn)程結(jié)合起來分析。線程是比進(jìn)程更小的執(zhí)行單位。一個(gè)進(jìn)程在其執(zhí)行過程中,可以產(chǎn)生多個(gè)線程,形成多條執(zhí)行點(diǎn),每條執(zhí)行點(diǎn)即每個(gè)線程。線程有它自身的產(chǎn)生、存在和消亡的過程,它是一個(gè)動(dòng)態(tài)的概念。線程很像進(jìn)程,它們?cè)诟拍钌鲜窍嚓P(guān)的。它們都是代表著程序當(dāng)前的運(yùn)行情況,都是執(zhí)行一定的任務(wù),而且它們都是可以并行并發(fā)執(zhí)行的。
2.線程的狀態(tài)與生命周期
每個(gè)Java程序都有一個(gè)默認(rèn)的主線程,對(duì)于Java的應(yīng)用程序,主線程是main()方法執(zhí)行的線索;對(duì)于App let程序,主線程是指揮瀏覽器加載并執(zhí)行Java App let程序的線索。要想實(shí)現(xiàn)多線程,必須在主線程中創(chuàng)建新的線程對(duì)象。任何一個(gè)線程,在它的一個(gè)完整生命周期中通常具有創(chuàng)建、就緒、運(yùn)行、阻塞和終止五種狀態(tài)。在給定的時(shí)間點(diǎn)上,一個(gè)線程只能處于一種狀態(tài)。圖1顯示了一個(gè)Java線程在它的生命周期中的各個(gè)狀態(tài)。
圖1 線程的生命周期
3.線程的調(diào)度及優(yōu)先級(jí)
每個(gè)線程都有一個(gè)優(yōu)先級(jí),它在線程被創(chuàng)建時(shí)其優(yōu)先級(jí)是由創(chuàng)建它的線程所決定的;也可以在線程創(chuàng)建之后的任意時(shí)刻通過調(diào)用setPriority的方法來修改線程的優(yōu)先級(jí)。線程的優(yōu)先級(jí)是在M IN_PRIORITY和MA X_PRlORITY范圍內(nèi)的一個(gè)整數(shù)值,數(shù)值越大,代表線程的優(yōu)先級(jí)越高。
當(dāng)一個(gè)線程進(jìn)入運(yùn)行狀態(tài)之后,這個(gè)線程就稱為是被“調(diào)度”或被線程調(diào)度管理器選中了。在Ja2 va系統(tǒng)中,線程調(diào)度依據(jù)優(yōu)先級(jí)基礎(chǔ)上的“先到先服務(wù)”原則。在任意時(shí)刻,當(dāng)有多個(gè)線程處于可運(yùn)行狀態(tài),運(yùn)行系統(tǒng)總是挑選一個(gè)優(yōu)先級(jí)最高的線程執(zhí)行,只有當(dāng)線程停止、退出或者由于某種原因不執(zhí)行的時(shí)候,低優(yōu)先級(jí)的線程才可以被執(zhí)行。如果當(dāng)高優(yōu)先級(jí)的線程處于阻塞狀態(tài),并且CPU處于空閑時(shí),低優(yōu)先級(jí)的線程會(huì)被調(diào)度執(zhí)行;另外若有兩個(gè)相同優(yōu)先級(jí)的線程同時(shí)等待執(zhí)行時(shí),運(yùn)行系統(tǒng)會(huì)以round-robin的方式選擇一個(gè)執(zhí)行。
在Java中,實(shí)現(xiàn)多線程的應(yīng)用有兩種方式:一種是繼承 Thread類來創(chuàng)建對(duì)象用戶,另一種是聲明實(shí)現(xiàn)了Runnable接口的類。兩種方式都需要使用到Java基礎(chǔ)類庫中的Thread類及其方法。
1.通過繼承 Thread類實(shí)現(xiàn)多線程
用Thread類實(shí)現(xiàn)多線程,用戶需要在程序中創(chuàng)建自己的 Thread類的子類和重新定義一個(gè)自己的run()方法,這個(gè)run()方法中包含了用戶線程的操作。run()方法是定義在 Thread類里的一個(gè)方法,因此把線程的程序代碼編寫在run()方法內(nèi),事實(shí)上所做的就是覆寫的操作。這樣在程序需要建立線程時(shí),它只需要?jiǎng)?chuàng)建一個(gè)已定義好的Thread類的子類的實(shí)例就可以了。用Thread類實(shí)現(xiàn)多線程定義的語法如下:
class類名稱extends Thread //從 Thread類擴(kuò)展出子類
{
屬性……
方法……
修飾符 run(){ //覆寫 Thread類里的run()方法
以線程處理的程序;}
}
用此方法,在一個(gè)Java App lication程序中定義兩個(gè)類,一個(gè)是程序的主類 TestThread,另一個(gè)是用戶自定義的 Thread類的子類p rimeThread。程序的主線程,即 TestThread主類的main()方法首先根據(jù)用戶輸入的命令行參數(shù)創(chuàng)建一個(gè)p rimeThread類的對(duì)象,并調(diào)用start()方法啟動(dòng)這個(gè)子線程對(duì)象,使之進(jìn)入就緒狀態(tài)。主線程首先輸出一行信息表示自己在活動(dòng),然后調(diào)用sleep()方法使自己休眠一段時(shí)間以便子線程獲取處理器,進(jìn)入運(yùn)行狀態(tài)的子線程將檢查一個(gè)數(shù)值是否是素?cái)?shù)并顯示出來,然后也休眠一段時(shí)間以便父線程獲得處理器。獲得處理器的父線程將顯示一行信息表示自己在活動(dòng),然后再休眠……每次子線程啟動(dòng)都檢查一個(gè)新的增大一個(gè)的數(shù)值是否為素?cái)?shù)并打印,直至該數(shù)大于其預(yù)定的上限。此時(shí)子線程從run()方法返回并結(jié)束其運(yùn)行,然后主線程也結(jié)束。
2.通過實(shí)現(xiàn)Runnable接口實(shí)現(xiàn)多線程
用創(chuàng)建Thread子類的方法雖然簡便易用,但是要求必須有一個(gè)以 Thread為父類的用戶子類。假設(shè)用戶子類需要有另一個(gè)父類,則根據(jù)Java程序只允許單一繼承的原則,就不能用 Thread類產(chǎn)生線程了,因?yàn)镴ava不允許多繼承,這時(shí)我們可以考慮使用Runnable接口的方法來創(chuàng)建線程。其定義的語法如下:
class類名稱 imp lem ents Runnable //實(shí)現(xiàn)Runnable接口
{
屬性……
方法……
修飾符 run(){ //覆寫 Thread類里的run()方法
以線程處理的程序;}
}
Runnable接口只有一個(gè)方法run(),實(shí)現(xiàn)這個(gè)接口就必須要定義run()方法的具體內(nèi)容,用戶新建線程的操作也由這個(gè)方法來決定。Runnable接口中的這個(gè)run()方法是一個(gè)較特殊的方法,它可以被運(yùn)行系統(tǒng)自動(dòng)識(shí)別和執(zhí)行。定義好run()方法之后,當(dāng)用戶程序需要建立新線程時(shí),只要以這個(gè)實(shí)現(xiàn)了run()方法的類為參數(shù)創(chuàng)建系統(tǒng)類Thread的對(duì)象,就可以把用戶實(shí)現(xiàn)的run()方法繼承過來。所以,一個(gè)實(shí)現(xiàn)了Runnable接口的類實(shí)際上定義了一個(gè)主線程之外的新線程的操作,而定義新線程的操作和執(zhí)行流程,是實(shí)現(xiàn)多線程應(yīng)用的最主要工作之一。
3.兩種實(shí)現(xiàn)機(jī)制的比較
不管實(shí)現(xiàn)了Runnable接口還是繼承了 Thread類,兩種多線程機(jī)制運(yùn)行的結(jié)果都是一樣的。經(jīng)分析可見,實(shí)現(xiàn)Runnable接口相對(duì)于繼承Thread類來說,有如下三個(gè)顯著優(yōu)勢(shì)。
(1)適合多個(gè)相同程序代碼的線程去處理同一資源的情況,把虛擬CPU(線程)同程序的代碼、數(shù)據(jù)有效分離,較好地體現(xiàn)了面向?qū)ο蟮脑O(shè)計(jì)思想。
(2)可以避免由于Java的單繼承特性帶來的局限。
(3)增強(qiáng)了程序的健壯性,代碼能夠被多個(gè)線程共享,代碼與數(shù)據(jù)是獨(dú)立的。當(dāng)多個(gè)線程的執(zhí)行代碼來自同一個(gè)類的實(shí)例時(shí),即稱它們共享相同的代碼。
由于 Thread類實(shí)現(xiàn)了Runnable接口,也就是說 Thread類也是Runnable接口的一個(gè)子類。在實(shí)際的開發(fā)中,幾乎所有多線程的應(yīng)用都可以使用實(shí)現(xiàn)Runnable接口。
4.多線程實(shí)現(xiàn)應(yīng)用實(shí)例
在程序中,多線程的實(shí)現(xiàn)可以通過創(chuàng)建 Thread類的子類和通過實(shí)現(xiàn)Runnable接口兩個(gè)途徑來完成。無論采用哪種途徑,程序員在編程中可以用定義用戶線程的run()方法與建立用戶線程實(shí)例來控制兩個(gè)關(guān)鍵性操作。用實(shí)現(xiàn)Runnable接口的方法實(shí)現(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(“第一個(gè)子線程”);
Label p romp t2=new Label(“第二個(gè)子線程”);
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();//啟動(dòng)線程對(duì)象,進(jìn)入就緒狀態(tài)
thread2.start();}
public void run()//實(shí)現(xiàn)Runnable接口的run()方法,在該線程啟動(dòng)時(shí)自動(dòng)執(zhí)行
{
String currentRunning;
w hile(true)
{
try
{//使當(dāng)前活動(dòng)線程休眠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)度”);}
}}}
這是一個(gè)Java App let,所以程序的主類 TestRunnable必須是App let類的子類;同時(shí)它還實(shí)現(xiàn)了Runnable接口并具體實(shí)現(xiàn)了run()方法。在TestRunnable中創(chuàng)建了兩個(gè)子線程,都是Thread類的對(duì)象。這兩個(gè)對(duì)象的構(gòu)造函數(shù)指明它們將繼承當(dāng)前類中的run()方法,即它們被調(diào)度時(shí)將執(zhí)行這個(gè)run()方法。這個(gè)run()方法將首先休眠一段隨機(jī)的時(shí)間,然后統(tǒng)計(jì)當(dāng)前活動(dòng)(即獲得了處理器的)線程被調(diào)度次數(shù)并顯示在相應(yīng)的文本框中。
[1]李相國等.Java實(shí)例精通[M].北京:機(jī)械工業(yè)出版社,2009.
[2]印旻.Java語言與面向?qū)ο蟪绦蛟O(shè)計(jì)[M].北京:清華大學(xué)出版社,2002.
[3]袁加全.基于Java多線程的有限元并行計(jì)算的研究[D].天津:天津工業(yè)大學(xué),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-),男,天津市人,大學(xué)本科學(xué)歷,天津機(jī)電職業(yè)技術(shù)學(xué)院講師,主要研究方向?yàn)橛?jì)算機(jī)應(yīng)用技術(shù)、軟件工程。