




版權(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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 個人租房押付三合同
- 廣告設(shè)計制作合同協(xié)議書
- 客車駕駛員聘用協(xié)議書
- 分期付款設(shè)備買賣合同
- 物資倉庫裝修施工方案
- 下部結(jié)構(gòu)施工方案
- 宿遷住宅防水施工方案
- 安徽省部分學(xué)校2024-2025學(xué)年高三下學(xué)期3月調(diào)研考試歷史試題(原卷版+解析版)
- 暖氣片施工方案
- 泡沫箱和紙箱加工生產(chǎn)線環(huán)評報告表
- 2024年常德職業(yè)技術(shù)學(xué)院單招職業(yè)技能測試題庫及答案解析
- 模板工程風(fēng)險辨識及防范措施
- 《紅樓夢第五回》課件2
- 縫紉工(技師)理論考試復(fù)習(xí)題庫(匯總)
- 2024年中國移動校園招聘高頻考題難、易錯點模擬試題(共500題)附帶答案詳解
- 《C語言從入門到精通》培訓(xùn)教程課件
- 羔羊胃提取物維B12膠囊治療慢性萎縮性胃炎伴腸化的臨床療效觀察
- 2023年陜西省高中學(xué)業(yè)水平考試樣卷歷史試卷試題(含答案詳解)
- 2024年鎮(zhèn)江市高等專科學(xué)校高職單招(英語/數(shù)學(xué)/語文)筆試歷年參考題庫含答案解析
- 被人誹謗起訴狀
- 無人機技術(shù)在物流配送中的應(yīng)用
評論
0/150
提交評論