當前位置:學者齋 >

計算機 >java語言 >

Java多執行緒知識點

Java多執行緒知識點

引導語;多執行緒是指從軟體或者硬體上實現多個執行緒併發執行的技術。以下是本站小編分享給大家的Java多執行緒知識點,歡迎閱讀!

Java多執行緒知識點

  1.1多執行緒的概念

多執行緒程式設計的含義是你可將程式任務分成幾個並行的子任務。特別是在網路程式設計中,你會發現很多功能是可以併發執行的。比如網路傳輸速度較慢,使用者輸入速度較慢,你可以用兩個獨立的執行緒去完成這?copy;功能,而不影響正常的顯示或其他功能。多執行緒是與單執行緒比較而言的,普通的WINDOWS採用單執行緒程式結構,其工作原理是:主程式有一個訊息迴圈,不斷從訊息佇列中讀入訊息來決定下一步所要乾的事情,一般是一個子函式,只有等這個子函式執行完返回後,主程式才能接收另外的訊息來執行。比如子函式功能是在讀一個網路資料,或讀一個檔案,只有等讀完這?copy;資料或檔案才能接收下一個訊息。在執行這個子函式過程中你什麼也不能幹。但往往讀網路資料和等待使用者輸入有很多時間處於等待狀態,多執行緒利用這個特點將任務分成多個併發任務後,就可以解決這個問題。

  1.1.1Java執行緒的模型

Java的設計思想是建立在當前大多數作業系統都實現了執行緒排程。Java虛擬機器的很多工都依賴執行緒排程,而且所有的類庫都是為多執行緒設計的。實時上,Java支援Macintosh和Ms-dos的平臺?reg;所以遲遲未出來就是因為這兩個平臺都不支援多執行緒。Java利用多執行緒實現了整個執行環境是非同步的。在Java程式裡沒有主訊息迴圈。如果一個執行緒等待讀取網路資料,它可以執行但不停止系統的其他執行緒執行。用於處理使用者輸入的執行緒大多時間是等待使用者敲鍵盤或擊滑鼠。你還可以使動畫的每一幀?reg;間停頓一秒而並不使系統暫停。一?copy;執行緒啟動後,它可以被掛起,暫時不讓它執行。掛起的執行緒可以重新恢復執行。任何時間執行緒都可以被停止,被停止的執行緒就不能再重新啟動。Java語言裡,執行緒表現為執行緒類,執行緒類封裝了所有需要的執行緒操作控制。在你心裡,必須很清晰地區分開執行緒物件和執行執行緒,你可以將執行緒物件看作是執行執行緒的控制面板。線上程物件裡有很多函式來控制一個執行緒是否執行,睡眠,掛起或停止。執行緒類是控制執行緒行為的唯一的手段。一?copy;一個Java程式啟動後,就已經有一個執行緒在執行。你可通過呼叫Thread.currentThread函式來檢視當前執行的是哪一個執行緒。

你得到一個執行緒的控制柄,你就可以作很有趣的事情,即使單執行緒也一樣。下面這個例子讓你知道怎樣操縱當前執行緒。Filename:testthread

classtestthread{publicstaticvoidmain(Stringargs[]){Threadt

=Thread.currentThread();t.setName("ThisThreadisrunning");

System.out.println("Therunningthread:"+t);try{for(inti=0;i

{System.out.println("Sleeptime"+i);Thread.sleep(1000);}

}catch(InterruptedExceptione){System.out.println("threadhaswrong");}

}}

執行結果:javatestthreadTherunningthread:Thread[ThisThreadisrunning,5,main]Sleeptime0Sleeptime1Sleeptime2Sleeptime3Sleeptime4

  1.1.2啟動介面

一個執行緒並不激動人心,多個執行緒才有實際意義。我們怎樣建立更多的執行緒呢?我們需要建立執行緒類的另一個例項。當我們構造了執行緒類的一個新的例項,我們必須告訴它在新的執行緒裡應執行哪一段程式。你可以在任意實現了啟動介面的物件上啟動一個執行緒。啟動介面是一個抽象介面,來表示本物件有一?copy;函式想非同步執行。要實現啟動介面,一個類只需要有一個叫run的函式。下面是建立一個新執行緒的例子:

Filename:twothread.java

classtwothreadimplementsRunnable{twothread(){Threadt1

=Thread.currentThread();t1.setName("Thefirstmainthread");

System.out.println("Therunningthread:"+t1);Threadt2=new

Thread(this,"thesecondthread");System.out.println("creatanother

thread");t2.start();try{System.out.println("firstthreadwill

sleep");Thread.sleep(3000);}catch(InterruptedExceptione)

{System.out.println("firstthreadhaswrong");}

System.out.println("firstthreadexit");}publicvoidrun(){try{for

(inti=0;i

Thread.sleep(1000);}

}catch(InterruptedExceptione){System.out.println("threadhas

wrong");}

System.out.println("secondthreadexit");}publicstaticvoid

main(Stringargs[]){newtwothread();}}

執行結果:javatwothread

Therunningthread:Thread[Thefirstmainthread,5,main]creatanother

threadfirstthreadwillsleepSleeptimeforthread2:0Sleeptimefor

thread2:1Sleeptimeforthread2:2firstthreadexitSleeptimefor

thread2:3Sleeptimeforthread2:4secondthreadexit

main執行緒用newThread(this,"thesecondthread")建立了一個Thread物件,通過傳遞第一個引數來標明新執行緒來呼叫this物件的run函式。然後我們呼叫start函式,它將使執行緒從run函式開始執行。

  1.1.3同步

因為多執行緒給你提?copy;了程式的非同步執行的功能,所以在必要時必須還提?copy;一種同步機制。例如,你想兩個執行緒通訊並共享一個複雜的資料結構,你需要一種機制讓他們相互牽制並正確執行。為這個目的,Java用一種叫監視器(monitor)的機制實現了程序間的非同步執行。可以將監視器看作是一個很小的盒子,它只能容納一個執行緒。一?copy;一個執行緒進入一個監視器,所有其他執行緒必須等到第一個執行緒退出監視器後才能進入。這?copy;監視器可以設計成保護共享的資料不被多個執行緒同時操作。大多數多執行緒系統將這?copy;監視器設計成物件,Java提?copy;了一種更清晰的解決方案。沒有Monitor類;每個物件通過將他們的成員函式定義成synchronized來定義自己的顯式監視器,一?copy;一個執行緒執行在一個synchronized函式裡,其他任何執行緒都不能呼叫同一個物件的

synchronized函式。

  1.1.4訊息

你的程式被分成幾個邏輯執行緒,你必須清晰的'知道這?copy;執行緒?reg;間應怎樣相互通訊。Java提了wait和notify等功能來使執行緒?reg;間相互交談。一個執行緒可以進入某一個物件的synchronized函式進入等待狀態,直到其他執行緒顯式地將它喚醒。可以有多個執行緒進入同一個函式並等待同一個喚醒訊息。

  1.2Java執行緒例子

  1.2.1顯式定義執行緒

在我們的單執行緒應用程式裡,我們並沒有看見執行緒,因為Java能自動建立和控制你的執行緒。如果你使用了理解Java語言的瀏覽器,你就已經看到使用多執行緒的Java程式了。你也許注意到兩個小程式可以同時執行,或在你移動滾動條時小程式繼續執行。這並不是表明小程式是多執行緒的,但說明這個瀏覽器是多執行緒的。多執行緒應用程式(或applet)可以使用好幾個執行上下文來完成它們的工

作。多執行緒利用了很多工包含單獨的可分離的子任務的特點。每一個執行緒完成一個子任務。但是,每一個執行緒完成子任務時還是順序執行的。一個多執行緒程式允許各個執行緒儘快執行完它們。這種特點會有更好的實時輸入反應。

  1.2.2多執行緒例子

下面這個例子建立了三個單獨的執行緒,它們分別列印自己的"HelloWorld":

//Defineoursimplethreads.Theywillpauseforashorttime//andthen

printouttheirnamesanddelaytimesclassTestThreadextendsThread

{privateStringwhoami;privateintdelay;

//Ourconstructortostorethename(whoami)//andtimetosleep(delay)

publicTestThread(Strings,intd){whoami=s;delay=d;}

//Run-thethreadmethodsimilartomain()//Whenrunisfinished,the

threaddies.//Runiscalledfromthestart()methodofThreadpublicvoid

run(){//Trytosleepforthespecifiedtimetry{sleep(delay);}

catch(InterruptedExceptione){}//Nowprintoutourname

System.out.println("HelloWorld!"+whoami+""+delay);}}/***Multimtest.

Asimplemultithreadthestprogram*/publicclassmultitest{public

staticvoidmain(Stringargs[]){TestThreadt1,t2,t3;//Createourtest

threadst1=newTestThread("Thread1",(int)(Math.readom()*2000));t2=

newTestThread("Thread2",(int)(Math.readom()*2000));t3=new

TestThread("Thread3",(int)(Math.readom()*2000));

//Starteachofthethreadst1.start();t2.start();t3.start();}}

  1.2.3啟動一個執行緒

程式啟動時總是呼叫main()函式,因此main()是我們建立和啟動執行緒的地方:

t1=newTestThread("Thread1",(int)(Math.readom()*2000));

這一行建立了一個新的執行緒。後面的兩個引數傳遞了執行緒的名稱和執行緒在列印資訊?reg;前的延時時間。因為我們直接控制執行緒,我們必須直接啟動它:t1.start();

  1.2.4操作執行緒

如果建立執行緒正常,t1應包含一個有效的執行執行緒。我們線上程的run()函式裡控制執行緒。一?copy;我們進入run()函式,我們便可執行裡面的任何程式。run()好象main()一樣。

run()執行完,這個執行緒也就結束了。在這個例子裡,我們試著延遲一個隨機的時間(通過引數傳遞?)sleep(delay);

sleep()函式只是簡單地告訴執行緒休息多少個毫秒時間。

如果你想推遲一個執行緒的執行,你應使用sleep()函式。當執行緒睡眠是sleep()並不佔用系統資源。其它執行緒可繼續工作。一?copy;延遲時間完畢,它將列印"HelloWorld"和執行緒名稱及延遲時間。

  1.2.5暫停一個執行緒

我們經常需要掛起一個執行緒而不指定多少時間。例如,如果你建立了一個含有動畫執行緒的小程式。也許你讓使用者暫停動畫至到他們想恢復為止。你並不想將動畫執行緒仍調,但想讓它停止。象這種類似的執行緒你可用suspend()函式來控制:t1.suspend();這個函式並不永久地停止了執行緒,你還可用resume()函式重新啟用執行緒:t1.resume();

  1.2.6停止一個執行緒

執行緒的最後一個控制是停止函式stop()。我們用它來停止執行緒的執行:t1.stop();

注意:這並沒有消滅這個執行緒,但它停止了執行緒的執行。並且這個執行緒不能用t1.start()重新啟動。在我們的例子裡,我們從來不用顯式地停止一個執行緒。我們只簡單地讓它執行完而已。很多複雜的執行緒例子將需要我們控制每一個執行緒。在這種情況下會使用到stop()函式。如果需要,你可以測試你的執行緒是否被啟用。一個執行緒已經啟動而且沒有停止被認為是啟用的。t1.isAlive()如果t1是啟用的,這個函式將返回true.

  1.2.1動畫例子

下面是一個包含動畫執行緒的applet例子:

importjava.awt.*;importjava.awt.image.ImageProducer;import

java.applet.Applet;

publicclassatest3extendsAppletimplementsRunnable{Imageimages[];

MediaTrackertracker;intindex=0;Threadanimator;

intmaxWidth,maxHeight;//Ouroff-screencomponentsfordoublebuffering.

ImageoffScrImage;GraphicsoffScrGC;

//Canwepaintyes?booleanloaded=false;

//Initializetheapplet.Setoursizeandloadtheimagespublicvoidinit()

[//Setupourimagemonitortracker=newMediaTracker(this);

//SetthesizeandwidthofourappletmaxWidth=100;maxHeight=100;

images=newImage[10];//Setupthedouble-bufferandresizeourapplet

try{offScrImage=createImage(maxWidth,maxHeight);offScrGC=

offScrImage.getGraphics();offScrGC.setColor(Color.lightGray);

offScrGC.fillRect(0,0,maxWidth,maxHeight);

resize(maxWidth,maxHeight);}catch(Exceptione)

{e.printStackTrace();}

//loadtheanimationimagesintoanarrayfor(inti=0;i

imageFile=newString("images/Duke/T"+String.valueOf(i+1)+".gif");

images[i]=getImage(getDocumentBase(),imageFile)://Registerthis

imagewiththetrackertracker.addImage(images[i],i);}try{//Use

trackertomakesurealltheimagesareloadedtracker.waitForAll();}

catch(InterruptedExceptione){}loaded=true;}

//Paintthecurrentframe.publicvoidpaint(Graphicsg){if(loaded)

{g.drawImage(offScrImage,0,0,this);}}

//Start,setupourfirstimagepublicvoidstart(){if(tracker.checkID

(index)){offScrGC.drawImage(images[index],0,0,this);}animator=new

Thread(this);animator.start();}

//Run,dotheanimationworkhere.//Grabanimage,pause,grabthenext...

publicvoidrun(){//GettheidofthecurrentthreadThreadme=

Thread.currentThread();

//Ifouranimatorthreadexist,andisthecurrentthread...while

((animatr!=null)&&(animator==me)){if(tracker.checkID(index))

{//Clearthebackgroundandgetthenextimage

offScrGC.fillRect(0,0,100,100);

offScrGCdrawImage(images[index],0,0,this);index++;//Loopbacktothe

beginningandkeepgoingif(index>=images.length){index=0;}}

//Delayheresoanimationlooksnormaltry{animator.sleep(200);}catch

(InterruptedExceptione){}//Drawthenextframerepaint();}}}

  1.3多執行緒間的通訊

  1.3.1生產者和消費者

多執行緒的一個重要特點是它們?reg;間可以互相通訊。你可以設計執行緒使用公用物件,每個執行緒都可以獨立操作公用物件。典型的執行緒間通訊建立在生產者和消費者模型上:一個執行緒產生輸出;另一個執行緒使用輸入buffer

讓我們建立一個簡單的"AlphabetSoup"生產者和相應的消費者.

  1.3.2生產者

生產者將從thread類裡派生:classProducerextendsThread

{privateSoupsoup;privateStringalphabet="

ABCDEFGHIJKLMNOPQRSTUVWXYZ";

publicProducer(Soups){//Keepourowncopyofthesharedobjectsoup

=s;}

publicvoidrun(){charc;//Throw10lettersintothesoupfor(int

i=0;i

soup.add(c);//printarecordofosraddition

System.out.println("Added"+c+"tothesoup.");//waitabitbeforewe

addthenextlettertry{sleep((int)(Math.random()*1000));}catch

(InterruptedExceptione){}}}}

注意我們建立了Soup類的一個例項。生產者用soup.add()函式來建立字元池。

  1.3.3消費者

讓我們看看消費者的程式:classConsumerextendsThread{privateSoupsoup;

publicConsumer(Soups){//keepourowncopyofthesharedobjectsoup

=s;}

publicvoidrun(){charc;//Eat10lettersfromthealphabetsoupfor

(intI=0;i

letterthatweretrievedSystem.out.println("Atealetter:"+c);//try

{sleep((int)(Math.raddom()*2000));}catch(InterruptedExceptione){}}}}

同理,象生產者一樣,我們用soup.eat()來處理資訊。那麼,Soup類到底幹什麼呢?

  1.3.4監視

Soup類執行監視兩個執行緒?reg;間傳輸資訊的功能。監視是多執行緒中不可缺少的一部分,因為它保持了通訊的流?copy;。讓我們看看Soup.java檔案:classSoup{privatecharbuffer[]=newchar[6];privateintnext=0;//Flagstokeeptrackof

ourbufferstatusprivatebooleanisFull=false;privatebooleanisEmpty

=true;publicsyschronizedchareat(){//Wecan'teatifthereisn'tanything

inthebufferwhile(isEmpty==true){try{wait();//we'llexitthis

whenisEmptyturnsfalse}catch(InterruptedExceptione){}}//decrement

thecount,sincewe'regoingtoeatoneletternext--;//Didweeatthe

lastletter?if(next==0){isEmpty=true;}//Weknowthebuffercan't

befull,becausewejustateisFull=false;notify();//returntheletter

tothethreadthatiseatingreturn(buffer[next]);}

//methodtoaddletterstothebufferpublicsynchronizedvoidadd(char

c){//Waitarounduntilthere'sroomtoaddanotherletterwhile(isFull

==true){try{wait();//ThiswillexitwhenisFullturnsfalse}catch

(InterruptedExceptione){}}//addthelettertothenextavailablespot

buffer[next]=c;//Changethenextavailablespotnext++;//Arewefull;

if(next==6){isFull=true;}isEmpty=false;notify();}}soup類包含兩個重要特徵:資料成員buffer[]是私有的,功能成員add()和eat()是公有的。

資料私有避免了生產者和消費者直接獲得資料。直接訪問資料可能造成錯誤。例如,如果消費者企圖從空緩衝區裡取出資料,你將得到不必要的異常,否則,你只能鎖住程序。同步訪問方法避免了破壞一個共享物件。當生產者向soup里加入一個字母時,消費者不能吃字元,諸如此類。這種同步是維持共享物件完整性的重要方面。notify()函式將喚醒每一個等待執行緒。等待執行緒將繼續它的訪問。

  1.3.5聯絡起來

現在我們有一個生產者,一個消費者和一個共享物件,怎樣實現它們的互動呢?我們只需要一個簡單的控制程式來啟動所有的執行緒並確信每一個執行緒都是訪問的同一個共享物件。下面是控制程式的程式碼,:

classSoupTest{publicstaticvoidmain(Stringargs[]){Soups=new

Soup();Producerp1=newProducer(s);Consumerc1=newConsumer(s);

t();t();}}

  1.3.6監視生產者

生產者/消費者模型程式經常用來實現遠端監視功能,它讓消費者看到生產者同用戶的互動或同系統其它部分的互動。例如,在網路中,一組生產者執行緒可以在很多工作站上執行。生產者可以列印文件,文件列印後,一個標誌將儲存下來。一個(或多個?copy;消費者將儲存標誌並在晚上報告白天列印活動的情況。另外,還有例子在一個工作站是分出幾個獨立的視窗。一個視窗用作使用者輸入(生產者)另一個視窗作出對輸入的反應(消費者)。

  1.4執行緒API列表

下面是一個常用的執行緒類的方法函式列表:類函式:以下是Thread的靜態函式,即可以直接從Thread類呼叫。

currentThread返回正在執行的Thread物件yield停止運行當前執行緒,讓系統執行下一個執行緒sleep(intn)讓當前執行緒睡眠n毫秒物件函式:以下函式必須用Thread的例項物件來呼叫。

startstart函式告訴java執行系統為本執行緒建立一個執行環境,然後呼叫本執行緒的run()函式。run是執行本執行緒的將要執行的程式碼,也是Runnable介面的唯一函式。當一個執行緒初始化後,由start函式來呼叫它,一?copy;run函式返回,本執行緒也就終止了。stop讓某執行緒馬上終止,系統將刪除本執行緒的執行環境suspend與stop函式不同,suspend將執行緒暫停執行,但系統不破壞執行緒的執行環境,你可以用resume來恢復本執行緒的執行resume恢復被掛起的執行緒進入執行狀態setPriority(intp)給執行緒設定優先順序getPriority返回執行緒的優先順序setName(Stringname)給執行緒設定名稱getName取執行緒的名稱

  • 文章版權屬於文章作者所有,轉載請註明 https://xuezhezhai.com/zh-tw/jsj/java/6gowe1.html