JAVA程序設(shè)計Java線程_第1頁
JAVA程序設(shè)計Java線程_第2頁
JAVA程序設(shè)計Java線程_第3頁
JAVA程序設(shè)計Java線程_第4頁
JAVA程序設(shè)計Java線程_第5頁
已閱讀5頁,還剩55頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

第8章Java線程?學(xué)習(xí)導(dǎo)讀本章將介紹Java線程編程技術(shù),以及多線程的同步和互斥。第8章Java線程線程基礎(chǔ)線程的生命多線程共享數(shù)據(jù)多線程的互斥和同步本章小結(jié)線程的概念多任務(wù):計算機在看上去幾乎同一時間內(nèi)運行多個程序。多線程:單個程序內(nèi)部也可以在同一時間進行多種運算。一個線程是一個程序內(nèi)部的順序控制流?!げ皇浅绦颍约罕旧聿荒苓\行,必須在程序中運行?!と绾卧谝粋€程序內(nèi)部實現(xiàn)多個線程?!?/p>

線程和進程·每個進程都有獨立的代碼和數(shù)據(jù)空間(進程上下文),進程切換的開銷大?!ぞ€程:輕量的進程,同一類線程共享代碼和數(shù)據(jù)空間,每個線程有獨立的運行棧和程序計數(shù)器

(PC),線程切換的開銷小?!ざ噙M程:在操作系統(tǒng)中,能同時運行多個任務(wù)

(程序)?!ざ嗑€程:在同一應(yīng)用程序中,有多個順序流同時執(zhí)行。線程的概念模型虛擬的CPU,封裝在java.lang.Thread類中。CPU所執(zhí)行的代碼,傳遞給Thread類。CPU所處理的數(shù)據(jù),傳遞給Thread類。線程體Java的線程是通過java.lang.Thread類來實現(xiàn)的。當(dāng)我們生成一個Thread類或者它的子類的對象后,一個新的線程就誕生了。每個線程都是通過某個特定Thread對象的方法run()來完成其操作的,方法run()稱為線程體。線程的狀態(tài)掛起,睡眠或等待喚醒創(chuàng)建狀態(tài)(new

Thread)Thread

myThread

=

new

MyThreadClass(

);可運行狀態(tài)(

Runnable

)

//非運行態(tài)Thread

myThread

=

new

MyThreadClass(

);myThread.start(

);·這一狀態(tài)并不是運行中狀態(tài)(Running),因為也許線程并未真正執(zhí)行,只有被調(diào)度執(zhí)行時,才真正處于運行狀態(tài)。不可運行狀態(tài)(Not

Runnable,Blocked)調(diào)用了sleep()方法;//此時線程的run()方法將中斷執(zhí)行調(diào)用了suspend()方法;//掛起線程,不推薦使用為等候一個條件變量,線程調(diào)用wait()方法;I/O處發(fā)生線程阻塞; //I/O阻塞對于上面四種情況,都有可以返回可運行態(tài)的方法與之對應(yīng)?!?.sleep()方法中的參數(shù)為休息時間,單位為毫秒,時間過去后,線程即為可運行的。//不是運行態(tài),需再次被調(diào)度·2.一個線程調(diào)用suspend()方法后,只能有其它線程調(diào)用它的resume()方法恢復(fù)?!?.如果一個線程等待條件變量,如果要停止等待,需要條件變量所在的對象調(diào)用notify()或者

notifyAll()方法。·4.特定的I/O指令完成,結(jié)束不可運行狀態(tài)。死亡狀態(tài)(Dead)線程的終止一般可通過兩種方法實現(xiàn):自然撤銷(線程執(zhí)行完)或是被停止(調(diào)用stop()方法,不推薦使用)。自然撤銷是線程的

run()方法正常退出。如下面的程序: public

void

run(){int

i=0;for

i=0;i<10;i++

){System.out.println(i);}}t.start();//t是一個線程…….. //省略了一些語句t.stop();//調(diào)用

stop()終止線程其它注意事項·1.非法狀態(tài)處理對于任何狀態(tài),如果調(diào)用的方法和狀態(tài)不符,都會引起非法狀態(tài)處理。例如,線程剛創(chuàng)建后,只能調(diào)用

start()或者stop()方法,如果調(diào)用其它方法就會引起非法狀態(tài)處理?!?.isAlive()方法在類Thread中提供了方法isAlive(),如果線程已經(jīng)啟動(start),但是未終止(dead),返回true,反之,返回

false,表示該線程未啟動,或者已終止。如果isAlive()方法返回true,不能區(qū)分是可運行態(tài)(runnable)還是不可運行態(tài)(not

runnable)。順序執(zhí)行(單線程)程序public

class

SequentialDemo{public

static

void

main(String

[]args){new

Sequential(“C").run();new

Sequential(“D").run();}}class

Sequential

extends

Thread

{String

name=null;public

Sequential(String

n){name=n;}public

void

run(){for(int

i=0;i<5;i++){try{//睡眠一段隨機時間

Thread.sleep((long)(Math.random()*

1000));}catch(InterruptedException

e){e.printStackTrace();}System.out.print(name);}}}每次總輸出結(jié)果:CCCCCDDDDD線程體的構(gòu)造(1)public

Thread();//創(chuàng)建一個線程對象(2)public

Thread(Runnable

target);//參數(shù)target的run()方法將被線程對象調(diào)用(3)public

Thread(String

name);

//線程的名稱(4)

public

Thread(Runnable

target,

String

name);(5)

public

Thread(

ThreadGroup

group,

Runnable

target);(6)

public

Thread(

ThreadGroup

group,

String

name);(7)

public

Thread(

ThreadGroup

group,

Runnable

target,String

name

);·group指明線程所在的組,可以把很多線程加在一個組里面,進行集中控制?!arget是執(zhí)行線程體的目標對象。生成這個對象的類,實現(xiàn)了

Runnable接口。其中包含線程體run()方法?!ame是線程的名稱。·任何實現(xiàn)接口Runnable的對象都可以作為一個線程的目標對象;·

構(gòu)造線程體的兩種方法·(1)定義一個線程類,它繼承類Thread并重寫其中的方法run();·(2)提供一個實現(xiàn)接口Runnable的類作為線程的目標對象,在初始化一個Thread類或者Thread子類的線程對象時,把目標對象傳遞給這個線程實例,由該目標對象提供線程體run()?!unnable接口中只定義了一個空方法run();(1)通過繼承類Thread構(gòu)造線程體class

SimpleThread

extends

Thread

{public

SimpleThread(String

str)

{super(str);}public

void

run()

{for

(int

i

=

0;

i

<

10;

i++)

{System.out.println(i

+

""

+getName());try

{sleep((int)(Math.random()

*

1000));}

catch

(InterruptedException

e)

{}}System.out.println("DONE!

"

+getName());}}public

class

TwoThreadsTest

{public

static

void

main

(String

args[])

{new

SimpleThread("First").start();new

SimpleThread("Second").start();}}運行結(jié)果:0

FirstSecondSecondFirstFirstSecondSecondFirstFirstSecondFirstSecondSecond6

First7

First7

Second8

Second9

Second8

FirstDONE!

Second9

FirstDONE!

First(2)通過接口構(gòu)造線程體-例子1class

SimpleThread

implements

Runnable{public

SimpleThread(String

str)

{//super(str);}public

void

run()

{for

(int

i

=

0;

i

<

10;

i++)

{System.out.println(i

+

"

"+Thread.currentThread().

getName());try

{Thread.sleep((int)(Math.random()

*

1000));}

catch

(InterruptedException

e)

{

}}(2)通過接口構(gòu)造線程體-例子1(續(xù))System.out.println("DONE!

"

+

Thread.currentThread().getName());}}public

class

TwoThreadsTest

{public

static

void

main

(String

args[])

{new

Thread(

new

SimpleThread(),"First").start();new

Thread(

new

SimpleThread(),“Second").start();}}例子1輸出結(jié)果0

First0

Second1

Second2

Second1

First3

Second4

Second2

First3

First4

First5

First5

Second6

First6

Second7

First7

Second8

First8

Second9

FirstDONE!9

SecondDONE!(2)通過接口構(gòu)造線程體-例子2public

class

Clock

extends

java.applet.Appletimplements

Runnable

{Thread

clockThread;public

void

start()

{if

(clockThread

==

null)

{clockThread

=

new

Thread(this,

"Clock");clockThread.start();}}public

void

run()

{while

(clockThread

!=

null)

{repaint();try

{clockThread.sleep(1000);}

catch

(InterruptedException

e){}}}public

void

paint(Graphics

g)

{Date

now

=

new

Date();g.drawString(now.getHours()

+

":"

+now.getMinutes()

+":"+now.

getSeconds(),

5,

10);}public

void

stop()

{clockThread.stop();clockThread

=

null;}}兩種方法的比較使用Runnable接口可以將CPU,代碼和數(shù)據(jù)分開,形成清晰的模型;還可以從其他類繼承;保持程序風(fēng)格的一致性;使用Thread.currentThread()獲取當(dāng)前線程進行控制。直接繼承Thread類不能再從其他類繼承;編寫簡單,可以直接操縱線程兩種構(gòu)造線程方法之間的關(guān)系線程的調(diào)度Java提供一個線程調(diào)度器來監(jiān)控程序中啟動后進入就緒狀態(tài)的所有線程。線程調(diào)度器按照線程的優(yōu)先級決定應(yīng)調(diào)度哪些線程來執(zhí)行。Java運行系統(tǒng)的線程調(diào)度算法是搶先式的(preemptive)?!r間片方式·非時間片方式·

下面幾種情況下,當(dāng)前線程會放棄CPU:·線程調(diào)用了yield()或sleep()方法主動放棄或它的run()方法結(jié)束;·由于當(dāng)前線程進行I/O訪問,外存讀寫,等待用戶輸入等操作,導(dǎo)致線程阻塞;·為等候一個條件變量,線程調(diào)用wait()方法;·搶先式系統(tǒng)下,由高優(yōu)先級的線程參與調(diào)度;·時間片方式下,當(dāng)前時間片用完,由同優(yōu)先級的線程參與調(diào)度。注意:使用yield()方法只能給同優(yōu)先級的線程提供執(zhí)行機會,如果沒有同優(yōu)先級的線程處于可運行態(tài),yield()將被忽略。線程的優(yōu)先級線程的優(yōu)先級用數(shù)字來表示,范圍從1到10,即Thread.MIN_PRIORITY(1)到

Thread.MAX_PRIORITY(10)。一個線程的缺省優(yōu)先級是5,即Thread.NORM_PRIORITY(5)。int

getPriority();void

setPriority(int

newPriority);class

ThreadTest{public

static

void

main(

String

args

[]

)

{Thread

t1

=

new

MyThread("T1");t1.setPriority(

Thread.MIN_PRIORITY

);t1.start(

);Thread

t2

=

new

MyThread("T2");t2.setPriority(

Thread.MAX_PRIORITY

);t2.start(

);Thread

t3

=

new

MyThread("T3");t3.setPriority(

Thread.MAX_PRIORITY

);t3.start(

);}}class

MyThread

extends

Thread

{String

message;MyThread

(

String

message

)

{this.message

=

message;}public

void

run()

{for

(

int

i=0;

i<3;

i++

)System.out.println(message+“

"+getPriority());}}運行結(jié)果:T210T210T210T310T310T310T11T11T11·

注意:并不是在所有系統(tǒng)中運行Java程序時都采用時間片策略調(diào)度線程,所以一個線程在空閑時應(yīng)該主動放棄CPU,以使其他同優(yōu)先級和低優(yōu)先級的線程得到執(zhí)行?;镜木€程控制終止線程·線程執(zhí)行完其run()方法后,會自然終止?!ねㄟ^調(diào)用線程的實例方法stop()來終止線程。測試線程狀態(tài)·可以通過Thread中的isAlive()方法來獲取線程是否處于活動狀態(tài);·線程由start()方法啟動后,直到其被終止之間的任何時刻,都處于‘Alive’狀態(tài)。·

線程的暫停和恢復(fù)·sleep()方法·suspend()和resume()方法·join()方法當(dāng)前線程等待調(diào)用該方法的線程結(jié)束后,再恢復(fù)執(zhí)行。TimerThread

tt=new

TimerThread(100);tt.start();…public

void

timeout(){tt.join();

//等待線程tt執(zhí)行完后再繼續(xù)往下執(zhí)行…

}多線程的互斥與同步線程1線程2線程10資源取過來加1后送回去withdrwal()withdrwal()透支余額變量多線程的互斥與同步·臨界資源問題class

stack{int

idx=0;char[

]

data

=

new

char[6];public

void

push(char

c){data[idx]

=

c;idx++;}public

char

pop(){idx--;return

data[idx];}}兩個線程A和B在同時使用Stack的同一個實例對象,

A正在往堆棧里push一個數(shù)據(jù),B則要從堆棧中pop

一個數(shù)據(jù)。操作之前

data

=

|

p

|

q

|

|

|

|

|

idx=2A執(zhí)行push中的第一個語句,將r推入堆棧;data

=

|

p

|

q

|

r

|

|

|

|

idx=23)

A還未執(zhí)行idx++語句,A的執(zhí)行被B中斷,B執(zhí)行pop方法,返回q:data=|

p

|

q

|

r

|

|

|

|

idx=14)A繼續(xù)執(zhí)行push的第二個語句:data=|

p

|

q

|

r

|

|

|

|

idx=2最后的結(jié)果相當(dāng)于r沒有入棧?!?/p>

產(chǎn)生這種問題的原因在于對共享數(shù)據(jù)訪問的操作的不完整性?!?/p>

在Java語言中,引入了對象互斥鎖的概念,來保證共享數(shù)據(jù)操作的完整性?!っ總€對象都對應(yīng)于一個可稱為“互斥鎖”的標記,這個標記用來保證在任一時刻,只能有一個線程訪問該對象?!ava運行系統(tǒng)允許一個線程再次取得已為自己控制的對象鎖,即對象鎖是可重入的?!りP(guān)鍵字synchronized

來與對象的互斥鎖聯(lián)系。當(dāng)某個對象用synchronized修飾時,表明該對

象在任一時刻只能由一個線程訪問。public

void

push(char

c){//synchronized實例方法是使用this鎖去做線程的//共享互斥synchronized(this){data[idx]=c;idx++;}}public

char

pop(){synchronized(this){idx--;return

data[idx];}}synchronized除了象上面講的放在對象前面限制一段代碼的執(zhí)行外,還可以放在方法聲明中,表示整個方法為同步方法。方法在執(zhí)行時需要獲取“互斥鎖”,是一個原子方法,不會被外界中斷。public

synchronized

void

push(char

c){…}如果synchronized用在類聲明中,則表明該類中的所有方法都是synchronized的。多線程的同步//同步化的堆棧類,定義了兩個同步方法

class

SyncStack{private

int

index

=

0;private

char[

]

buffer

=

new

char[6];public

synchronized

void

push(char

c){while(index

==

buffer.length){try{//或wait();等待消費者取走數(shù)據(jù)}catch(InterruptedExceptionthis.wait();e){

}}//最好使用notifyAll(),通知消費者可以來取//數(shù)據(jù)

this.notify();buffer[index]=c;index++;}public

synchronized

char

pop(){while(index

==0){try{//或wait();等待生產(chǎn)者生產(chǎn)數(shù)據(jù)this.wait();}catch(InterruptedException

e){

}}//最好使用notifyAll(),通知生產(chǎn)者可以再次寫入//數(shù)據(jù)this.notify();index-

-;return

buffer[index];}}·注意:方法notifyAll()喚醒的是由于等待notifyAll()方法所在對象(這里是SyncStack)的所有線程,被喚醒的線程會去競爭對象鎖,當(dāng)其中某個線程得到鎖之后,其他的線程重新進入阻塞狀態(tài)。而

notify()方法是不安全的,因為你無法控制讓哪一個線程離開阻塞隊列。如果讓一個不合適的線程離開等待隊列,它也可能仍無法向前

運行。因此建議使用notifyAll()方法,讓等待隊列上的所有和當(dāng)前對象相關(guān)的線程離開阻塞狀態(tài)。生產(chǎn)者-消費者問題//生產(chǎn)者線程class

Producer

implements

Runnable{SyncStack

theStack;public

Producer(SyncStack

s){theStack

=

s;}資源

SyncStack生產(chǎn)者消費者public

void

run(){char

c;for(int

i=0;

i<20;

i++){c=(char)(Math.random()*26+"A");theStack.push(c);System.out.println("Produced:"+c);try{//當(dāng)前線程中斷執(zhí)行run()方法,進入//阻塞狀態(tài),給其他線程以執(zhí)行的機會Thread.sleep((int)(Math.random()*100));}catch(InterruptedException

e){}}}}//消費者線程class

Consumer

implements

Runnable{SyncStack

theStack;public

Consumer(SyncStack

s){theStack

=

s;}public

void

run(){char

c;for(int

i=0;i<20;i++){c

=

theStack.pop();System.out.println("Consumed:

"+c);try{Thread.sleep((int)(Math.random()*1000));}catch(InterruptedException

e){

}}}}//模擬生產(chǎn)者-消費者問題的主程序public

class

SyncTest{public

static

void

main(String

args[]){SyncStack

stack

=

new

SyncStack();Runnable

source=new

Producer(stack);Runnable

sink

=

new

Consumer(stack);Thread

t1

=

new

Thread(source);

Thread

t2

=

new

Thread(sink);t1.start();t2.start();}}程序執(zhí)行結(jié)果Produced:VConsumed:VProduced:EConsumed:EProduced:PProduced:L...Consumed:LConsumed:Pwait(),

notify(),

notifyAll()wait,nofity,notifyAll必須在已經(jīng)持有鎖的情況下執(zhí)行,所以它們只能出現(xiàn)在synchronized作用的范圍內(nèi)。這些方法都是在java.lang.Object中定義的。wait的作用:釋放已持有的鎖,進入wait隊列。notify的作用:喚醒wait隊列中的一個線程,并把它移入鎖申請隊列。notifyAll的作用:喚醒wait隊列中的所有的線程并把它們移入鎖申請隊列.模擬考題Question

1)Which

of

the

following

are

methodsof

the

Runnable

interfacerunstartyieldstop模擬考題Answer

to

Question

1)1)

The

Runnable

interface

has

onlyone

method

run

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論