摘要:線程是程序執(zhí)行流的最小單元。四線程和八線程是線程的兩種表現(xiàn)形式,下面來(lái)看看它們之間的區(qū)別以及線程的實(shí)現(xiàn)方式。
線程介紹
線程,有時(shí)被稱(chēng)為輕量級(jí)進(jìn)程(Lightweight Process,LWP),是程序執(zhí)行流的最小單元。一個(gè)標(biāo)準(zhǔn)的線程由線程ID,當(dāng)前指令指針(PC),寄存器集合和堆棧組成。另外,線程是進(jìn)程中的一個(gè)實(shí)體,是被系統(tǒng)獨(dú)立調(diào)度和分派的基本單位,線程自己不擁有系統(tǒng)資源,只擁有一點(diǎn)兒在運(yùn)行中必不可少的資源,但它可與同屬一個(gè)進(jìn)程的其它線程共享進(jìn)程所擁有的全部資源。
一個(gè)線程可以創(chuàng)建和撤消另一個(gè)線程,同一進(jìn)程中的多個(gè)線程之間可以并發(fā)執(zhí)行。由于線程之間的相互制約,致使線程在運(yùn)行中呈現(xiàn)出間斷性。線程也有就緒、阻塞和運(yùn)行三種基本狀態(tài)。就緒狀態(tài)是指線程具備運(yùn)行的所有條件,邏輯上可以運(yùn)行,在等待處理機(jī);運(yùn)行狀態(tài)是指線程占有處理機(jī)正在運(yùn)行;阻塞狀態(tài)是指線程在等待一個(gè)事件(如某個(gè)信號(hào)量),邏輯上不可執(zhí)行。每一個(gè)程序都至少有一個(gè)線程,若程序只有一個(gè)線程,那就是程序本身。
線程適用范圍
1.服務(wù)器中的文件管理或通信控制
2.前后臺(tái)處理
3.異步處理
線程特點(diǎn)
在多線程O(píng)S中,通常是在一個(gè)進(jìn)程中包括多個(gè)線程,每個(gè)線程都是作為利用CPU的基本單位,是花費(fèi)最小開(kāi)銷(xiāo)的實(shí)體。線程具有以下屬性。
1)輕型實(shí)體
線程中的實(shí)體基本上不擁有系統(tǒng)資源,只是有一點(diǎn)必不可少的、能保證獨(dú)立運(yùn)行的資源。
線程的實(shí)體包括程序、數(shù)據(jù)和TCB。線程是動(dòng)態(tài)概念,它的動(dòng)態(tài)特性由線程控制塊TCB(Thread Control Block)描述。TCB包括以下信息:
1)線程狀態(tài)。
(2)當(dāng)線程不運(yùn)行時(shí),被保存的現(xiàn)場(chǎng)資源。
?。?)一組執(zhí)行堆棧。
(4)存放每個(gè)線程的局部變量主存區(qū)。
?。?)訪問(wèn)同一個(gè)進(jìn)程中的主存和其它資源。
用于指示被執(zhí)行指令序列的程序計(jì)數(shù)器、保留局部變量、少數(shù)狀態(tài)參數(shù)和返回地址等的一組寄存器和堆棧。
2)獨(dú)立調(diào)度和分派的基本單位。
在多線程O(píng)S中,線程是能獨(dú)立運(yùn)行的基本單位,因而也是獨(dú)立調(diào)度和分派的基本單位。由于線程很“輕”,故線程的切換非常迅速且開(kāi)銷(xiāo)小(在同一進(jìn)程中的)。
3)可并發(fā)執(zhí)行。
在一個(gè)進(jìn)程中的多個(gè)線程之間,可以并發(fā)執(zhí)行,甚至允許在一個(gè)進(jìn)程中所有線程都能并發(fā)執(zhí)行;同樣,不同進(jìn)程中的線程也能并發(fā)執(zhí)行,充分利用和發(fā)揮了處理機(jī)與外圍設(shè)備并行工作的能力。
4)共享進(jìn)程資源。
在同一進(jìn)程中的各個(gè)線程,都可以共享該進(jìn)程所擁有的資源,這首先表現(xiàn)在:所有線程都具有相同的地址空間(進(jìn)程的地址空間),這意味著,線程可以訪問(wèn)該地址空間的每一個(gè)虛地址;此外,還可以訪問(wèn)進(jìn)程所擁有的已打開(kāi)文件、定時(shí)器、信號(hào)量機(jī)構(gòu)等。由于同一個(gè)進(jìn)程內(nèi)的線程共享內(nèi)存和文件,所以線程之間互相通信不必調(diào)用內(nèi)核。
線程的實(shí)現(xiàn)方式
Java中有兩種實(shí)現(xiàn)多線程的方式。一是直接繼承Thread類(lèi),二是實(shí)現(xiàn)Runnable接口。那么這兩種實(shí)現(xiàn)多線程的方式在應(yīng)用上有什么區(qū)別呢?
第一種方式:使用Runnable接口創(chuàng)建線程
1.可以將CPU,代碼和數(shù)據(jù)分開(kāi),形成清晰的模型
2.線程體run()方法所在的類(lèi)可以從其它類(lèi)中繼承一些有用的屬性和方法
3.有利于保持程序的設(shè)計(jì)風(fēng)格一致
第二種方式:直接繼承Thread類(lèi)創(chuàng)建對(duì)象
1.Thread子類(lèi)無(wú)法再?gòu)钠渌?lèi)繼承(java語(yǔ)言單繼承)。
2.編寫(xiě)簡(jiǎn)單,run()方法的當(dāng)前對(duì)象就是線程對(duì)象,可直接操作。
在實(shí)際應(yīng)用中,幾乎都采取第一種方式
我們用代碼來(lái)模擬鐵路售票系統(tǒng),實(shí)現(xiàn)通過(guò)四個(gè)售票點(diǎn)發(fā)售某日某次列車(chē)的100張車(chē)票,一個(gè)售票點(diǎn)用一個(gè)線程表示。
我們首先這樣編寫(xiě)這個(gè)程序:
Java代碼 class ThreadTest extends Thread{
private int ticket = 100;
public void run(){
while(true){
if(ticket 》 0){
System.out.println(Thread.currentThread().getName() +
“is saling ticket” + ticket--);
}else{
break;
}
}
}
}
main測(cè)試類(lèi):
Java代碼 public class ThreadDome1{
public static void main(String[] args){
ThreadTest t = new ThreadTest();
t.start();
t.start();
t.start();
t.start();
}
}
上面的代碼中,我們用ThreadTest類(lèi)模擬售票處的售票過(guò)程,run方法中的每一次循環(huán)都將總票數(shù)減1,模擬賣(mài)出一張車(chē)票,同時(shí)該車(chē)票號(hào)打印出來(lái),直接剩余的票數(shù)到零為止。在ThreadDemo1類(lèi)的main方法中,我們創(chuàng)建了一個(gè)線程對(duì)象,并重復(fù)啟動(dòng)四次,希望通過(guò)這種方式產(chǎn)生四個(gè)線程。從運(yùn)行的結(jié)果來(lái)看我們發(fā)現(xiàn)其實(shí)只有一個(gè)線程在運(yùn)行,這個(gè)結(jié)果告訴我們:一個(gè)線程對(duì)象只能啟動(dòng)一個(gè)線程,無(wú)論你調(diào)用多少遍start()方法,結(jié)果只有一個(gè)線程。
我們接著修改ThreadDemo1,在main方法中創(chuàng)建四個(gè)Thread對(duì)象:
Java代碼 public class ThreadDemo1{
public static void main(String[] args){
new ThreadTest().start();
new ThreadTest().start();
new ThreadTest().start();
new ThreadTest().start();
}
}
Java代碼 class ThreadTest extends Thread{
private int ticket = 100;
public void run(){
while(true){
if(ticket 》 0){
System.out.println(Thread.currentThread().getName() +
“ is saling ticket” + ticket--);
}else{
break;
}
}
}
}
從結(jié)果上看每個(gè)票號(hào)都被打印了四次,即四個(gè)線程各自賣(mài)各自的100張票,而不去賣(mài)共同的100張票。這種情況是怎么造成的呢?我們需要的是,多個(gè)線程去處理同一個(gè)資源,一個(gè)資源只能對(duì)應(yīng)一個(gè)對(duì)象,在上面的程序中,我們創(chuàng)建了四個(gè)ThreadTest對(duì)象,就等于創(chuàng)建了四個(gè)資源,每個(gè)資源都有100張票,每個(gè)線程都在獨(dú)自處理各自的資源。
經(jīng)過(guò)這些實(shí)驗(yàn)和分析,可以總結(jié)出,要實(shí)現(xiàn)這個(gè)鐵路售票程序,我們只能創(chuàng)建一個(gè)資源對(duì)象,但要?jiǎng)?chuàng)建多個(gè)線程去處理同一個(gè)資源對(duì)象,并且每個(gè)線程上所運(yùn)行的是相同的程序代碼。在回顧一下使用接口編寫(xiě)多線程的過(guò)程。
Java代碼 public class ThreadDemo1{
public static void main(String[] args){
ThreadTest t = new ThreadTest();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
}
}
Java代碼 class ThreadTest implements Runnable{
private int tickets = 100;
public void run(){
while(true){
if(tickets 》 0){
System.out.println(Thread.currentThread().getName() +
“ is saling ticket ” + tickets--);
}
}
}
}
上面的程序中,創(chuàng)建了四個(gè)線程,每個(gè)線程調(diào)用的是同一個(gè)ThreadTest對(duì)象中的run()方法,訪問(wèn)的是同一個(gè)對(duì)象中的變量(tickets)的實(shí)例,這個(gè)程序滿足了我們的需求。在Windows上可以啟動(dòng)多個(gè)記事本程序一樣,也就是多個(gè)進(jìn)程使用同一個(gè)記事本程序代碼。
可見(jiàn),實(shí)現(xiàn)Runnable接口相對(duì)于繼承Thread類(lèi)來(lái)說(shuō),有如下顯著的好處:
?。?)適合多個(gè)相同程序代碼的線程去處理同一資源的情況,把虛擬CPU(線程)同程序的代碼,數(shù)據(jù)有效的分離,較好地體現(xiàn)了面向?qū)ο蟮脑O(shè)計(jì)思想。
?。?)可以避免由于Java的單繼承特性帶來(lái)的局限。我們經(jīng)常碰到這樣一種情況,即當(dāng)我們要將已經(jīng)繼承了某一個(gè)類(lèi)的子類(lèi)放入多線程中,由于一個(gè)類(lèi)不能同時(shí)有兩個(gè)父類(lèi),所以不能用繼承Thread類(lèi)的方式,那么,這個(gè)類(lèi)就只能采用實(shí)現(xiàn)Runnable接口的方式了。
?
?。?)有利于程序的健壯性,代碼能夠被多個(gè)線程共享,代碼與數(shù)據(jù)是獨(dú)立的。當(dāng)多個(gè)線程的執(zhí)行代碼來(lái)自同一個(gè)類(lèi)的實(shí)例時(shí),即稱(chēng)它們共享相同的代碼。多個(gè)線程操作相同的數(shù)據(jù),與它們的代碼無(wú)關(guān)。當(dāng)共享訪問(wèn)相同的對(duì)象是,即它們共享相同的數(shù)據(jù)。當(dāng)線程被構(gòu)造時(shí),需要的代碼和數(shù)據(jù)通過(guò)一個(gè)對(duì)象作為構(gòu)造函數(shù)實(shí)參傳遞進(jìn)去,這個(gè)對(duì)象就是一個(gè)實(shí)現(xiàn)了Runnable接口的類(lèi)的實(shí)例。
四核四線程和四核八線程的區(qū)別
4核4線就是說(shuō)CPU有4個(gè)物理核心,所以任務(wù)管理器里就顯示出4張CPU圖表。
八線程,可以有2種情況, 物理4核和物理8核。
8核8線和前面4核4線一樣,4核8線 就是說(shuō),使用了超線程技術(shù),把一個(gè)物理核心,模擬成 2個(gè)邏輯核心,所以任務(wù)管理器會(huì)顯示出8張CPU表。
超線程技術(shù)讓?zhuān)≒4)處理器增加5%的裸晶面積,就可以換來(lái)15%~30%的效能提升。但實(shí)際上,在某些程式或未對(duì)多線程編譯的程式而言,超線程反而會(huì)降低效能。除此之外,超線程技術(shù)亦要操作系統(tǒng)的配合,普通支持多處理器技術(shù)的系統(tǒng)亦未必能充分發(fā)揮該技術(shù)。例如Windows 2000,英特爾并不鼓勵(lì)使用者在此系統(tǒng)中利用超線程。原先不支持多核心的Windows XP Home Edition卻支持超線程技術(shù)。
電子發(fā)燒友App























評(píng)論