Java基礎(chǔ):徹底搞懂java多線程
進(jìn)程與線程
進(jìn)程
進(jìn)程是操作系統(tǒng)結(jié)構(gòu)的基礎(chǔ),是程序在一個數(shù)據(jù)集合上運(yùn)行的過程,是系統(tǒng)進(jìn)行資源分配和調(diào)度的基本單位。進(jìn)程可以被看作程序的實(shí)體,同樣,它也是程序的容器。
線程
線程是操作系統(tǒng)調(diào)度的最小單元,也叫作輕量級進(jìn)程。在一個進(jìn)程中可以創(chuàng)建多個線程,這些線程都擁有各自的計數(shù)器、堆棧和局部變量等屬性。
使用多線程的優(yōu)勢
- 使用多線程可以減少程序的響應(yīng)時間
如果某個操作很耗時,或者陷入長時間的等待,此時程序?qū)⒉粫憫?yīng)鼠標(biāo)和鍵盤等的操作,使用多線程后可以把這個耗時的操作分配到一個單獨(dú)的線程中執(zhí)行,從而使程序具備了更好的交互性。
- 與進(jìn)程相對,線程創(chuàng)建和切換開銷更小,同時多線程在數(shù)據(jù)共享方面效率非常高。
- 多CPU 或者多核計算機(jī)本身就具備執(zhí)行多線程的能力。
如果使用單個線程,將無法重復(fù)利用計算機(jī)資源,這會造成資源的巨大浪費(fèi)。在多CPU計算機(jī)中使用多線程能提高CPU的利用率。
- 使用多線程能簡化程序的結(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)。一個可運(yùn)行的線程可能正在運(yùn)行也可能沒有運(yùn)行,這取決于操作系統(tǒng)給線程提供運(yùn)行的時間。
- Blocked
阻塞狀態(tài)。表示線程被鎖阻塞,它暫時不活動。
- Waiting
等待狀態(tài)。線程暫時不活動,并且不運(yùn)行任何代碼,這消耗最少資源,直到線程調(diào)度器重新激活它。
- Timed waiting
超時等待狀態(tài)。和等待不同的是,它是可以在指定的時間自行返回的。
- Terminated
終止?fàn)顟B(tài)。表示當(dāng)前線程已經(jīng)執(zhí)行完畢。導(dǎo)致線程終止有兩種情況:(1)run方法執(zhí)行完畢正常退出;(2)因?yàn)橐粋€沒有捕獲取得異常而終止了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)。超時等待相當(dāng)于在等待狀態(tài)加上了時間限制,如果超過時間限制,則線程返回運(yùn)行狀態(tài)。當(dāng)線程調(diào)用到同步方法時,如果線程沒有獲得鎖則進(jìn)入阻塞狀態(tài),當(dāng)阻塞狀態(tài)的線程獲取到鎖時則重新回到運(yùn)行狀態(tài)。當(dāng)線程執(zhí)行完畢或者遇到意外異常終止時,都會進(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ù)接受后提供一個返回值,Runnable無法提供這個功能。
- Callable中的call()方法可以拋出異常,而Runnable的run()方法不能拋出異常。
- 運(yùn)行Callable可以拿到一個Future對象,F(xiàn)uture對象表示異步計算的結(jié)果,它提供了檢查計算是否完成的方法。
- 由于線程屬于異步計算模型,因此無法從別的線程中得到函數(shù)的返回值,在這種情況下就可以使用Future來監(jiān)視目標(biāo)線程調(diào)用call()方法的情況。但調(diào)用Future的get()方法以獲取結(jié)果時,當(dāng)前線程就會阻塞,直到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)沒有捕獲的異常時,線程將終止。interrupt方法可以用來請求中斷線程。當(dāng)一個線程調(diào)用interrupt方法時,線程的中斷標(biāo)識位為true,線程會不時地檢測這個中斷標(biāo)識位,以判斷線程是否應(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)識位會復(fù)位,即重新設(shè)置為false),讓外界通過Thread.currentThread().isInterrupted() 來決定是否終止還是繼續(xù)下去。
void task() throw InterrupetedException{
sleep(50);
}
不用try來捕獲異常,讓方法直接拋出,這樣調(diào)用者可以捕獲這個異常。
中斷線程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é)
- 如果一個線程處于阻塞狀態(tài),線程在檢查中斷標(biāo)識位時,如果發(fā)現(xiàn)中斷標(biāo)識位為true,則會在阻塞方法調(diào)用處拋出InterruptedException 異常,并且在拋出異常前將線程的中斷標(biāo)識位復(fù)位,即重新設(shè)置為false。
- 被中斷的線程不一定會終止,中斷線程是為了引起線程的注意,被中斷的線程可以決定如何去響應(yīng)中斷。如果是比較重要的線程則不會理會中斷,而大部分情況則是線程會將中斷作為一個終止的請求。
本篇文章就到這里了,希望能給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
SpringBoot項(xiàng)目Pom文件的基本配置方式
這篇文章主要介紹了SpringBoot項(xiàng)目Pom文件的基本配置方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-06-06
Java微信公眾平臺開發(fā)(9) 關(guān)鍵字回復(fù)以及客服接口實(shí)現(xiàn)
這篇文章主要為大家詳細(xì)介紹了Java微信公眾平臺開發(fā)第九步,關(guān)鍵字回復(fù)以及客服接口實(shí)現(xiàn),以及遇到該公眾號暫時無法提供服務(wù)的解決方案,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-04-04
詳解Springboot集成sentinel實(shí)現(xiàn)接口限流入門
這篇文章主要介紹了詳解Springboot集成sentinel實(shí)現(xiàn)接口限流入門,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
關(guān)于IDEA關(guān)聯(lián)數(shù)據(jù)庫的問題
這篇文章主要介紹了IDEA關(guān)聯(lián)數(shù)據(jù)庫的相關(guān)知識,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-03-03

