Java基礎(chǔ):徹底搞懂java多線程
進(jìn)程與線程
進(jìn)程
進(jìn)程是操作系統(tǒng)結(jié)構(gòu)的基礎(chǔ),是程序在一個(gè)數(shù)據(jù)集合上運(yùn)行的過(guò)程,是系統(tǒng)進(jìn)行資源分配和調(diào)度的基本單位。進(jìn)程可以被看作程序的實(shí)體,同樣,它也是程序的容器。
線程
線程是操作系統(tǒng)調(diào)度的最小單元,也叫作輕量級(jí)進(jìn)程。在一個(gè)進(jìn)程中可以創(chuàng)建多個(gè)線程,這些線程都擁有各自的計(jì)數(shù)器、堆棧和局部變量等屬性。
使用多線程的優(yōu)勢(shì)
- 使用多線程可以減少程序的響應(yīng)時(shí)間
如果某個(gè)操作很耗時(shí),或者陷入長(zhǎng)時(shí)間的等待,此時(shí)程序?qū)⒉粫?huì)響應(yīng)鼠標(biāo)和鍵盤(pán)等的操作,使用多線程后可以把這個(gè)耗時(shí)的操作分配到一個(gè)單獨(dú)的線程中執(zhí)行,從而使程序具備了更好的交互性。
- 與進(jìn)程相對(duì),線程創(chuàng)建和切換開(kāi)銷(xiāo)更小,同時(shí)多線程在數(shù)據(jù)共享方面效率非常高。
- 多CPU 或者多核計(jì)算機(jī)本身就具備執(zhí)行多線程的能力。
如果使用單個(gè)線程,將無(wú)法重復(fù)利用計(jì)算機(jī)資源,這會(huì)造成資源的巨大浪費(fèi)。在多CPU計(jì)算機(jī)中使用多線程能提高CPU的利用率。
- 使用多線程能簡(jiǎn)化程序的結(jié)構(gòu),使程序便于理解和維護(hù)。
線程的狀態(tài)
- New
新創(chuàng)建狀態(tài)。線程被創(chuàng)建,還沒(méi)有調(diào)用start方法,在線程運(yùn)行之前還有一些基礎(chǔ)工作要做。
- Runnable
可運(yùn)行狀態(tài)。一旦調(diào)用start方法,線程就處于Runnable 狀態(tài)。一個(gè)可運(yùn)行的線程可能正在運(yùn)行也可能沒(méi)有運(yùn)行,這取決于操作系統(tǒng)給線程提供運(yùn)行的時(shí)間。
- Blocked
阻塞狀態(tài)。表示線程被鎖阻塞,它暫時(shí)不活動(dòng)。
- Waiting
等待狀態(tài)。線程暫時(shí)不活動(dòng),并且不運(yùn)行任何代碼,這消耗最少資源,直到線程調(diào)度器重新激活它。
- Timed waiting
超時(shí)等待狀態(tài)。和等待不同的是,它是可以在指定的時(shí)間自行返回的。
- Terminated
終止?fàn)顟B(tài)。表示當(dāng)前線程已經(jīng)執(zhí)行完畢。導(dǎo)致線程終止有兩種情況:(1)run方法執(zhí)行完畢正常退出;(2)因?yàn)橐粋€(gè)沒(méi)有捕獲取得異常而終止了run 方法,導(dǎo)致線程進(jìn)入終止?fàn)顟B(tài)。
線程創(chuàng)建后,調(diào)用Thead的start方法,開(kāi)始進(jìn)入運(yùn)行狀態(tài),當(dāng)線程執(zhí)行wait方法后,線程進(jìn)入等待狀態(tài),進(jìn)入等待狀態(tài)的線程需要其他線程通知才能返回運(yùn)行狀態(tài)。超時(shí)等待相當(dāng)于在等待狀態(tài)加上了時(shí)間限制,如果超過(guò)時(shí)間限制,則線程返回運(yùn)行狀態(tài)。當(dāng)線程調(diào)用到同步方法時(shí),如果線程沒(méi)有獲得鎖則進(jìn)入阻塞狀態(tài),當(dāng)阻塞狀態(tài)的線程獲取到鎖時(shí)則重新回到運(yùn)行狀態(tài)。當(dāng)線程執(zhí)行完畢或者遇到意外異常終止時(shí),都會(huì)進(jìn)入終止?fàn)顟B(tài)。
創(chuàng)建線程
- 繼承Thread類(lèi),重寫(xiě)run()方法
- 實(shí)現(xiàn)Runnable接口,并實(shí)現(xiàn)該接口的Run()方法 (推薦)
public class ThreadExample2 extends Thread{ public static void main(String[] args) { Thread mThread=new ThreadExample2(); mThread.start(); } @Override public void run() { System.out.print("thread excute"); } }
- 實(shí)現(xiàn)Callable接口,重寫(xiě)call()方法
public class ThreadExample { public static void main(String[] args) { ExRunnable runnable=new ExRunnable(); Thread mThread=new Thread(runnable); mThread.start(); } } public class ExRunnable implements Runnable{ @Override public void run() { System.out.print("thread excute"); } }
Callable接口是屬于Executor框架中的功能類(lèi)。Callable可以在任務(wù)接受后提供一個(gè)返回值,Runnable無(wú)法提供這個(gè)功能。
- Callable中的call()方法可以拋出異常,而Runnable的run()方法不能拋出異常。
- 運(yùn)行Callable可以拿到一個(gè)Future對(duì)象,F(xiàn)uture對(duì)象表示異步計(jì)算的結(jié)果,它提供了檢查計(jì)算是否完成的方法。
- 由于線程屬于異步計(jì)算模型,因此無(wú)法從別的線程中得到函數(shù)的返回值,在這種情況下就可以使用Future來(lái)監(jiān)視目標(biāo)線程調(diào)用call()方法的情況。但調(diào)用Future的get()方法以獲取結(jié)果時(shí),當(dāng)前線程就會(huì)阻塞,直到call()方法返回結(jié)果。
public class ThreadExample { public static void main(String[] args) { ExCallable mCallable=new ExCallable(); ExecutorService mExecutorService=Executors.newSingleThreadExecutor(); Future<String> mFuture=mExecutorService.submit(mCallable); try { System.out.println(mFuture.get()); } catch (Exception e) { e.printStackTrace(); } } } public class ExCallable implements Callable<String> { @Override public String call() throws Exception { // TODO Auto-generated method stub return "thread excute"; } }
線程中斷
當(dāng)線程的run 方法執(zhí)行完畢,或者在方法中出現(xiàn)沒(méi)有捕獲的異常時(shí),線程將終止。interrupt方法可以用來(lái)請(qǐng)求中斷線程。當(dāng)一個(gè)線程調(diào)用interrupt方法時(shí),線程的中斷標(biāo)識(shí)位為true,線程會(huì)不時(shí)地檢測(cè)這個(gè)中斷標(biāo)識(shí)位,以判斷線程是否應(yīng)該被中斷。
// 判斷線程是否被中斷
Thread.currentThread().isInterrupted();
拋出InterruptedException 異常后,兩種處理方法:
void task(){ .... try{ sleep(50) }catch(InterruptedException e){ Thread.currentThread().interrupted(); } }
在catch子句中,調(diào)用Thread.currentThread().interrupted()來(lái)設(shè)置中斷狀態(tài)(因?yàn)閽伋霎惓:笾袛鄻?biāo)識(shí)位會(huì)復(fù)位,即重新設(shè)置為false),讓外界通過(guò)Thread.currentThread().isInterrupted() 來(lái)決定是否終止還是繼續(xù)下去。
void task() throw InterrupetedException{ sleep(50); }
不用try來(lái)捕獲異常,讓方法直接拋出,這樣調(diào)用者可以捕獲這個(gè)異常。
中斷線程Example
public class StopExampleThread { public static void main(String[] args) { // TODO Auto-generated method stub try { InterruptedRunnable mRunnable=new InterruptedRunnable(); Thread thread=new Thread(mRunnable,"threadDemo"); thread.start(); TimeUnit.MILLISECONDS.sleep(10); thread.interrupt(); } catch (InterruptedException e) { // 拋出InterruptedException后中斷標(biāo)志被清除 // 再次調(diào)用interrupt恢復(fù)中斷 Thread.currentThread().interrupt(); } } static class InterruptedRunnable implements Runnable{ int i=0; @Override public void run() { // TODO Auto-generated method stub while(!Thread.currentThread().isInterrupted()) { i++; System.out.println("i="+i); } System.out.println("stop"); } }
總結(jié)
- 如果一個(gè)線程處于阻塞狀態(tài),線程在檢查中斷標(biāo)識(shí)位時(shí),如果發(fā)現(xiàn)中斷標(biāo)識(shí)位為true,則會(huì)在阻塞方法調(diào)用處拋出InterruptedException 異常,并且在拋出異常前將線程的中斷標(biāo)識(shí)位復(fù)位,即重新設(shè)置為false。
- 被中斷的線程不一定會(huì)終止,中斷線程是為了引起線程的注意,被中斷的線程可以決定如何去響應(yīng)中斷。如果是比較重要的線程則不會(huì)理會(huì)中斷,而大部分情況則是線程會(huì)將中斷作為一個(gè)終止的請(qǐng)求。
本篇文章就到這里了,希望能給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
java之向linux文件夾下寫(xiě)文件無(wú)權(quán)限的問(wèn)題
這篇文章主要介紹了java之向linux文件夾下寫(xiě)文件無(wú)權(quán)限的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09JavaWeb實(shí)現(xiàn)自動(dòng)登錄功能
這篇文章主要為大家詳細(xì)介紹了JavaWeb實(shí)現(xiàn)自動(dòng)登錄功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08JAVA編程實(shí)現(xiàn)TCP網(wǎng)絡(luò)通訊的方法示例
這篇文章主要介紹了JAVA編程實(shí)現(xiàn)TCP網(wǎng)絡(luò)通訊的方法,簡(jiǎn)單說(shuō)明了TCP通訊的原理并結(jié)合具體實(shí)例形式分析了java實(shí)現(xiàn)TCP通訊的步驟與相關(guān)操作技巧,需要的朋友可以參考下2017-08-08SpringSecurity 自定義表單登錄的實(shí)現(xiàn)
這篇文章主要介紹了SpringSecurity 自定義表單登錄的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01SpringAOP切點(diǎn)函數(shù)實(shí)現(xiàn)原理詳解
這篇文章主要介紹了SpringAOP切點(diǎn)函數(shù)實(shí)現(xiàn)原理詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05Java實(shí)現(xiàn)紅黑樹(shù)(平衡二叉樹(shù))的詳細(xì)過(guò)程
紅黑樹(shù)接近平衡的二叉樹(shù),插入,刪除函數(shù)跟平衡二叉樹(shù)一樣,只是平衡函數(shù)不同,下面這篇文章主要給大家介紹了關(guān)于Java實(shí)現(xiàn)紅黑樹(shù)(平衡二叉樹(shù))的相關(guān)資料,需要的朋友可以參考下2021-10-10利用JDBC的PrepareStatement打印真實(shí)SQL的方法詳解
PreparedStatement是預(yù)編譯的,對(duì)于批量處理可以大大提高效率. 也叫JDBC存儲(chǔ)過(guò)程,下面這篇文章主要給大家介紹了關(guān)于利用JDBC的PrepareStatement打印真實(shí)SQL的方法,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-07-07面試官:java ThreadLocal真的會(huì)造成內(nèi)存泄露嗎
ThreadLocal,java面試過(guò)程中的“釘子戶”,在網(wǎng)上也充斥著各種有關(guān)ThreadLocal內(nèi)存泄露的問(wèn)題,本文換個(gè)角度,先思考ThreadLocal體系中的ThreadLocalMap為什么要設(shè)計(jì)成弱引用2021-08-08