溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Java多線程的基礎(chǔ)知識講解

發(fā)布時間:2021-08-24 21:09:27 來源:億速云 閱讀:132 作者:chen 欄目:編程語言

本篇內(nèi)容介紹了“Java多線程的基礎(chǔ)知識講解”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細閱讀,能夠?qū)W有所成!

1、什么是多線程

在早期的計算機中時沒有操作系統(tǒng)的,計算機開啟后只能執(zhí)行一個程序,直到結(jié)束。操作系統(tǒng)的出現(xiàn)使得計算機可以同時執(zhí)行多個程序,操作系統(tǒng)為每個程序分配不同的進程,每個進程擁有獨立的句柄、資源等,使得計算機可以同時執(zhí)行多個程序。但是進程的創(chuàng)建和銷毀耗費的代價太大,因此衍生出線程的概念。允許在一個進程中創(chuàng)建多個線程,這些線程共享進程的資源,并且每個線程擁有自己獨立的程序計數(shù)器、線程局部變量等資源。線程也被稱為進程的輕量型運動實體。

2、創(chuàng)建多線程和啟動

(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();

3、多線程的優(yōu)勢

多線程的出現(xiàn)帶來很多的好處:

(1)發(fā)揮多核處理器的性能:在多喝處理器上執(zhí)行單線程任務(wù)是對多核的浪費,因為總有核心在空閑著,多線程的出現(xiàn)能充分發(fā)揮多核的優(yōu)勢。

(2)化整為零:往往在一個復(fù)雜的應(yīng)用中包含許多不同類型的任務(wù),將這些不同類型的任務(wù)分配給不同的線程去執(zhí)行會比將其混在同一個線程中去執(zhí)行要好,因為每個線程更加的簡單清晰,更容易測試等。

(3)異步事件處理:當一個線程處理的任務(wù)遇到阻塞時如IO阻塞,cpu可以調(diào)度其他線程去執(zhí)行而不是在那傻傻的等到IO結(jié)束在執(zhí)行其他任務(wù)。

(5)更好的用戶體驗:當多個用戶像你的服務(wù)發(fā)送請求時,你一個線程依次執(zhí)行任務(wù)會使得排在后面的用戶等待時間過長得不到響應(yīng),帶來不好的體驗。但使用多個線程可以讓每個用戶都能很快的得到響應(yīng)(盡管這不能高執(zhí)行速度),用戶會覺得自己的請求正在被處理,獲得更好的體驗。

4、多線程的生命周期

(1)新建狀態(tài)

用new關(guān)鍵字和Thread類或其子類建立一個線程對象后,該線程對象就處于新生狀態(tài)。處于新生狀態(tài)的線程有自己的內(nèi)存空間,通過調(diào)用start方法進入就緒狀態(tài)(runnable)。

注意:不能對已經(jīng)啟動的線程再次調(diào)用start()方法,否則會出現(xiàn)Java.lang.IllegalThreadStateException異常。

(2)就緒狀態(tài)

處于就緒狀態(tài)的線程已經(jīng)具備了運行條件,但還沒有分配到CPU,處于線程就緒隊列(盡管是采用隊列形式,事實上,把它稱為可運行池而不是可運行隊列。因為cpu的調(diào)度不一定是按照先進先出的順序來調(diào)度的),等待系統(tǒng)為其分配CPU。等待狀態(tài)并不是執(zhí)行狀態(tài),當系統(tǒng)選定一個等待執(zhí)行的Thread對象后,它就會從等待執(zhí)行狀態(tài)進入執(zhí)行狀態(tài),系統(tǒng)挑選的動作稱之為“cpu調(diào)度”。一旦獲得CPU,線程就進入運行狀態(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)。

注: 當發(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)該盡量避免使用該方法。

當線程的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并暫時停止自己的運行,進入阻塞狀態(tài)。 在阻塞狀態(tài)的線程不能進入就緒隊列。只有當引起阻塞的原因消除時,如睡眠時間已到,或等待的I/O設(shè)備空閑下來,線程便轉(zhuǎn)入就緒狀態(tài),重新到就緒隊列中排隊等待,被系統(tǒng)選中后從原來停止的位置開始繼續(xù)運行。有三種方法可以暫停Threads執(zhí)行:

(5)死亡狀態(tài)

當線程的run()方法執(zhí)行完,或者被強制性地終止,就認為它死去。這個線程對象也許是活的,但是,它已經(jīng)不是一個單獨執(zhí)行的線程。線程一旦死亡,就不能復(fù)生。 如果在一個死去的線程上調(diào)用start()方法,會拋出java.lang.IllegalThreadStateException異常。

“Java多線程的基礎(chǔ)知識講解”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI