更新時間:2020-06-05 15:46:51 來源:動力節(jié)點 瀏覽2146次
Java多線程教程,Java支持多線程編程,因此用Java編寫的應(yīng)用程序可以同時執(zhí)行多個任務(wù)。Java的多線程機制使用起來非常方便,用戶只需關(guān)注程序細(xì)節(jié)的實現(xiàn),而不用擔(dān)心后臺的多任務(wù)系統(tǒng)。本文將為大家講解有關(guān)Java多線程的基礎(chǔ)知識,主要內(nèi)容有多線程的概念、創(chuàng)建、優(yōu)勢和生命周期。
在早期的計算機中時沒有操作系統(tǒng)的,計算機開啟后只能執(zhí)行一個程序,直到結(jié)束。操作系統(tǒng)的出現(xiàn)使得計算機可以同時執(zhí)行多個程序,操作系統(tǒng)為每個程序分配不同的進(jìn)程,每個進(jìn)程擁有獨立的句柄、資源等,使得計算機可以同時執(zhí)行多個程序。但是進(jìn)程的創(chuàng)建和銷毀耗費的代價太大,因此衍生出線程的概念。允許在一個進(jìn)程中創(chuàng)建多個線程,這些線程共享進(jìn)程的資源,并且每個線程擁有自己獨立的程序計數(shù)器、線程局部變量等資源。線程也被稱為進(jìn)程的輕量型運動實體。
1.繼承Thread類創(chuàng)建線程類
通過繼承Thread類創(chuàng)建線程類的具體步驟和具體代碼如下:
定義一個繼承Thread類的子類,并重寫該類的run()方法;
創(chuàng)建Thread子類的實例,即創(chuàng)建了線程對象;
調(diào)用該線程對象的start()方法啟動線程。
class SomeThead extends Thraad{
public void run(){
//do something here
}
}
public static void main(String[]args){
SomeThread oneThread=new SomeThread();
步驟3:啟動多線程:
oneThread.start();
}
2.實現(xiàn)Runnable接口創(chuàng)建線程類
通過實現(xiàn)Runnable接口創(chuàng)建線程類的具體步驟和具體代碼如下:
定義Runnable接口的實現(xiàn)類,并重寫該接口的run()方法;
創(chuàng)建Runnable實現(xiàn)類的實例,并以此實例作為Thread的target對象,即該Thread對象才是真正的線程對象。
class SomeRunnable implements Runnable{
public void run(){
//do something here
}
}
Runnable oneRunnable=new SomeRunnable();
Thread oneThread=new Thread(oneRunnable);
oneThread.start();
3.通過Callable和Future創(chuàng)建線程
通過Callable和Future創(chuàng)建線程的具體步驟和具體代碼如下:
創(chuàng)建Callable接口的實現(xiàn)類,并實現(xiàn)call()方法,該call()方法將作為線程執(zhí)行體,并且有返回值。
創(chuàng)建Callable實現(xiàn)類的實例,使用FutureTask類來包裝Callable對象,該FutureTask對象封裝了該Callable對象的call()方法的返回值。
使用FutureTask對象作為Thread對象的target創(chuàng)建并啟動新線程。
調(diào)用FutureTask對象的get()方法來獲得子線程執(zhí)行結(jié)束后的返回值其中,Callable接口(也只有一個方法)定義如下:
public interface Callable{
V call()throws Exception;
}
步驟1:創(chuàng)建實現(xiàn)Callable接口的類SomeCallable(略);
步驟2:創(chuàng)建一個類對象:
Callable oneCallable=new SomeCallable();
步驟3:由Callable創(chuàng)建一個FutureTask對象:
FutureTask oneTask=new FutureTask(oneCallable);
注釋:FutureTask是一個包裝器,它通過接受Callable來創(chuàng)建,它同時實現(xiàn)了Future和Runnable接口。
步驟4:由FutureTask創(chuàng)建一個Thread對象:
Thread oneThread=new Thread(oneTask);
步驟5:啟動線程:
oneThread.start();
多線程的出現(xiàn)帶來很多的好處:
1.新建狀態(tài)
用new關(guān)鍵字和Thread類或其子類建立一個線程對象后,該線程對象就處于新生狀態(tài)。處于新生狀態(tài)的線程有自己的內(nèi)存空間,通過調(diào)用start方法進(jìn)入就緒狀態(tài)(runnable)。
注意:不能對已經(jīng)啟動的線程再次調(diào)用start()方法,否則會出現(xiàn)Java.lang.IllegalThreadStateException異常。
2.就緒狀態(tài)
處于就緒狀態(tài)的線程已經(jīng)具備了運行條件,但還沒有分配到CPU,處于線程就緒隊列(盡管是采用隊列形式,事實上,把它稱為可運行池而不是可運行隊列。因為cpu的調(diào)度不一定是按照先進(jìn)先出的順序來調(diào)度的),等待系統(tǒng)為其分配CPU。等待狀態(tài)并不是執(zhí)行狀態(tài),當(dāng)系統(tǒng)選定一個等待執(zhí)行的Thread對象后,它就會從等待執(zhí)行狀態(tài)進(jìn)入執(zhí)行狀態(tài),系統(tǒng)挑選的動作稱之為“cpu調(diào)度”。一旦獲得CPU,線程就進(jìn)入運行狀態(tài)并自動調(diào)用自己的run方法。
提示:如果希望子線程調(diào)用start()方法后立即執(zhí)行,可以使用Thread.sleep()方式使主線程睡眠一伙兒,轉(zhuǎn)去執(zhí)行子線程。
3.運行狀態(tài)
處于運行狀態(tài)的線程最為復(fù)雜,它可以變?yōu)樽枞麪顟B(tài)、就緒狀態(tài)和死亡狀態(tài)。
處于就緒狀態(tài)的線程,如果獲得了cpu的調(diào)度,就會從就緒狀態(tài)變?yōu)檫\行狀態(tài),執(zhí)行run()方法中的任務(wù)。如果該線程失去了cpu資源,就會又從運行狀態(tài)變?yōu)榫途w狀態(tài)。重新等待系統(tǒng)分配資源。也可以對在運行狀態(tài)的線程調(diào)用yield()方法,它就會讓出cpu資源,再次變?yōu)榫途w狀態(tài)。
注:當(dāng)發(fā)生如下情況是,線程會從運行狀態(tài)變?yōu)樽枞麪顟B(tài):
①線程調(diào)用sleep方法主動放棄所占用的系統(tǒng)資源
②線程調(diào)用一個阻塞式IO方法,在該方法返回之前,該線程被阻塞
③線程試圖獲得一個同步監(jiān)視器,但更改同步監(jiān)視器正被其他線程所持有
④線程在等待某個通知(notify)
⑤程序調(diào)用了線程的suspend方法將線程掛起。不過該方法容易導(dǎo)致死鎖,所以程序應(yīng)該盡量避免使用該方法。
當(dāng)線程的run()方法執(zhí)行完,或者被強制性地終止,例如出現(xiàn)異常,或者調(diào)用了stop()、desyory()方法等等,就會從運行狀態(tài)轉(zhuǎn)變?yōu)樗劳鰻顟B(tài)。
4.阻塞狀態(tài)
處于運行狀態(tài)的線程在某些情況下,如執(zhí)行了sleep(睡眠)方法,或等待I/O設(shè)備等資源,將讓出CPU并暫時停止自己的運行,進(jìn)入阻塞狀態(tài)。在阻塞狀態(tài)的線程不能進(jìn)入就緒隊列。只有當(dāng)引起阻塞的原因消除時,如睡眠時間已到,或等待的I/O設(shè)備空閑下來,線程便轉(zhuǎn)入就緒狀態(tài),重新到就緒隊列中排隊等待,被系統(tǒng)選中后從原來停止的位置開始繼續(xù)運行。有三種方法可以暫停Threads執(zhí)行:
5.死亡狀態(tài)
當(dāng)線程的run()方法執(zhí)行完,或者被強制性地終止,就認(rèn)為它死去。這個線程對象也許是活的,但是,它已經(jīng)不是一個單獨執(zhí)行的線程。線程一旦死亡,就不能復(fù)生。如果在一個死去的線程上調(diào)用start()方法,會拋出java.lang.IllegalThreadStateException異常。
以上就是動力節(jié)點java培訓(xùn)機構(gòu)的小編針對“Java多線程教程之基礎(chǔ)知識講解”的內(nèi)容進(jìn)行的回答,希望對大家有所幫助,如有疑問,請在線咨詢,有專業(yè)老師隨時為你服務(wù)。
相關(guān)閱讀