Java基礎(chǔ):徹底搞懂java多線程
進(jìn)程與線程
進(jìn)程
進(jìn)程是操作系統(tǒng)結(jié)構(gòu)的基礎(chǔ),是程序在一個(gè)數(shù)據(jù)集合上運(yùn)行的過程,是系統(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)和鍵盤等的操作,使用多線程后可以把這個(gè)耗時(shí)的操作分配到一個(gè)單獨(dú)的線程中執(zhí)行,從而使程序具備了更好的交互性。
- 與進(jìn)程相對(duì),線程創(chuàng)建和切換開銷更小,同時(shí)多線程在數(shù)據(jù)共享方面效率非常高。
- 多CPU 或者多核計(jì)算機(jī)本身就具備執(zhí)行多線程的能力。
如果使用單個(gè)線程,將無法重復(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)建,還沒有調(diào)用start方法,在線程運(yùn)行之前還有一些基礎(chǔ)工作要做。
- Runnable
可運(yùn)行狀態(tài)。一旦調(diào)用start方法,線程就處于Runnable 狀態(tài)。一個(gè)可運(yùn)行的線程可能正在運(yùn)行也可能沒有運(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è)沒有捕獲取得異常而終止了run 方法,導(dǎo)致線程進(jìn)入終止?fàn)顟B(tài)。

線程創(chuàng)建后,調(diào)用Thead的start方法,開始進(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í)間限制,如果超過時(shí)間限制,則線程返回運(yùn)行狀態(tài)。當(dāng)線程調(diào)用到同步方法時(shí),如果線程沒有獲得鎖則進(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類,重寫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接口,重寫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框架中的功能類。Callable可以在任務(wù)接受后提供一個(gè)返回值,Runnable無法提供這個(gè)功能。
- Callable中的call()方法可以拋出異常,而Runnable的run()方法不能拋出異常。
- 運(yùn)行Callable可以拿到一個(gè)Future對(duì)象,F(xiàn)uture對(duì)象表示異步計(jì)算的結(jié)果,它提供了檢查計(jì)算是否完成的方法。
- 由于線程屬于異步計(jì)算模型,因此無法從別的線程中得到函數(shù)的返回值,在這種情況下就可以使用Future來監(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)沒有捕獲的異常時(shí),線程將終止。interrupt方法可以用來請(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()來設(shè)置中斷狀態(tài)(因?yàn)閽伋霎惓:笾袛鄻?biāo)識(shí)位會(huì)復(fù)位,即重新設(shè)置為false),讓外界通過Thread.currentThread().isInterrupted() 來決定是否終止還是繼續(xù)下去。
void task() throw InterrupetedException{
sleep(50);
}
不用try來捕獲異常,讓方法直接拋出,這樣調(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)求。
本篇文章就到這里了,希望能給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
java之向linux文件夾下寫文件無權(quán)限的問題
這篇文章主要介紹了java之向linux文件夾下寫文件無權(quán)限的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09
JavaWeb實(shí)現(xiàn)自動(dòng)登錄功能
這篇文章主要為大家詳細(xì)介紹了JavaWeb實(shí)現(xiàn)自動(dòng)登錄功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08
JAVA編程實(shí)現(xiàn)TCP網(wǎng)絡(luò)通訊的方法示例
這篇文章主要介紹了JAVA編程實(shí)現(xiàn)TCP網(wǎng)絡(luò)通訊的方法,簡(jiǎn)單說明了TCP通訊的原理并結(jié)合具體實(shí)例形式分析了java實(shí)現(xiàn)TCP通訊的步驟與相關(guān)操作技巧,需要的朋友可以參考下2017-08-08
SpringSecurity 自定義表單登錄的實(shí)現(xiàn)
這篇文章主要介紹了SpringSecurity 自定義表單登錄的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01
SpringAOP切點(diǎn)函數(shù)實(shí)現(xiàn)原理詳解
這篇文章主要介紹了SpringAOP切點(diǎn)函數(shù)實(shí)現(xiàn)原理詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05
Java實(shí)現(xiàn)紅黑樹(平衡二叉樹)的詳細(xì)過程
紅黑樹接近平衡的二叉樹,插入,刪除函數(shù)跟平衡二叉樹一樣,只是平衡函數(shù)不同,下面這篇文章主要給大家介紹了關(guān)于Java實(shí)現(xiàn)紅黑樹(平衡二叉樹)的相關(guān)資料,需要的朋友可以參考下2021-10-10
利用JDBC的PrepareStatement打印真實(shí)SQL的方法詳解
PreparedStatement是預(yù)編譯的,對(duì)于批量處理可以大大提高效率. 也叫JDBC存儲(chǔ)過程,下面這篇文章主要給大家介紹了關(guān)于利用JDBC的PrepareStatement打印真實(shí)SQL的方法,需要的朋友可以參考借鑒,下面來一起看看吧。2017-07-07
面試官:java ThreadLocal真的會(huì)造成內(nèi)存泄露嗎
ThreadLocal,java面試過程中的“釘子戶”,在網(wǎng)上也充斥著各種有關(guān)ThreadLocal內(nèi)存泄露的問題,本文換個(gè)角度,先思考ThreadLocal體系中的ThreadLocalMap為什么要設(shè)計(jì)成弱引用2021-08-08

