文章目錄
- 一、概念
- 1、進(jìn)程
- 2、線程
- 3、CPU與線程的關(guān)系
- 4、并行、并發(fā)
- 5、線程的生命周期
- 二、創(chuàng)建
- 1、繼承Thread
- 2、實(shí)現(xiàn)Runnable接口
- 3、實(shí)現(xiàn)Callable接口
- 三、API
- 1、獲取運(yùn)行使用的線程
- 2、唯一標(biāo)識(shí)
- 3、線程名
- 4、優(yōu)先級(jí)
- 5、是否處于活動(dòng)狀態(tài)
- 6、守護(hù)線程
- 7、join
-
- 8、yield
- 9、sleep
- 10、線程中斷
一、概念
1、進(jìn)程
2、線程
- 是1個(gè)進(jìn)程(程序內(nèi)部)的1條執(zhí)行路徑
- 單線程:1個(gè)進(jìn)程中只有1個(gè)線程(1條執(zhí)行路徑)
- 多線程:1個(gè)進(jìn)程中包含多個(gè)線程(多條執(zhí)行路徑)
- 線程之間堆內(nèi)存、方法區(qū)內(nèi)存共享;但是棧內(nèi)存獨(dú)立,1個(gè)線程一個(gè)棧
3、CPU與線程的關(guān)系
- 單核CPU:不能夠做到真正的多線程并發(fā),因?yàn)樵谝粋€(gè)時(shí)間單元內(nèi),只能執(zhí)行一個(gè)線程的任務(wù),多個(gè)線程誰獲取時(shí)間片運(yùn)行誰,每個(gè)線程獲取時(shí)間片的概率相等,可能:t1、t2、t2、t2;給人一種多線程并發(fā)的感覺:其實(shí)是由于CPU的處理速度極快,多個(gè)線程之間頻繁切換執(zhí)行,跟人來的感覺是多個(gè)事情同時(shí)在做
4、并行、并發(fā)
- 并行:多核CPU同時(shí)執(zhí)行多個(gè)任務(wù)。比如:多個(gè)人同時(shí)做不同的事
- 并發(fā):單核CPU同時(shí)執(zhí)行多個(gè)任務(wù)。比如:多個(gè)人做同一件事
5、線程的生命周期
- 新建狀態(tài)
- 新建了線程對(duì)象,還沒調(diào)用start方法
- 就緒狀態(tài)
- 線程調(diào)用了start方法等待獲取CPU時(shí)間片
- 表示當(dāng)前線程具有搶奪CPU時(shí)間片的權(quán)力
- 運(yùn)行狀態(tài)
- 線程對(duì)象開始執(zhí)行run方法
- run方法的開始執(zhí)行標(biāo)志著這個(gè)線程進(jìn)入運(yùn)行狀態(tài),當(dāng)之前占有的CPU時(shí)間片用完之后,會(huì)重新回到就緒狀態(tài)繼續(xù)搶奪CPU時(shí)間片,當(dāng)再次搶到CPU時(shí)間之后,會(huì)重新進(jìn)入run方法接著上一次的代碼繼續(xù)往下執(zhí)行
- 阻塞狀態(tài)
- 當(dāng)一個(gè)線程遇到阻塞事件,例如:sleep方法、獲取synchronized排他鎖失敗(因?yàn)殒i被其它線程所占用)等,此時(shí)線程會(huì)進(jìn)入阻塞狀態(tài),阻塞狀態(tài)的線程會(huì)放棄之前占有的CPU時(shí)間片,之前的時(shí)間片沒了需要再次回到就緒狀態(tài)搶奪CPU時(shí)間片
- 死亡狀態(tài)
- run方法執(zhí)行完畢或者因異常退出了run方法,該線程生命周期結(jié)束
二、創(chuàng)建
1、繼承Thread
class Thread implements Runnable
- 缺點(diǎn):
- 由于java是單繼承的,這導(dǎo)致繼承了Thread后就不能在繼承其它類了;在實(shí)際開發(fā)中會(huì)經(jīng)常繼承某個(gè)超類來復(fù)用其中的方法,這導(dǎo)致兩者不能同時(shí)繼承
- 繼承線程后重寫run方法來定義任務(wù),這又導(dǎo)致我們將任務(wù)直接定義在線程上使得線程只能做該任務(wù),無法并發(fā)執(zhí)行其他任務(wù),重用性變差
public class HandleMsg extends Thread{private String threadKey;public HandleMsg(String threadKey){this.threadKey=threadKey;}@Overridepublic void run(){for(int i=0;i<10;i++){System.err.println(threadKey+":run");}}}
Thread t1=new Thread(()->{for(int i=0;i<10;i++) {System.err.println("t1:run");}
};
HandleMsg h1=new HandleMsg("h1");
HandleMsg h2=new HandleMsg("h2");
h1.start();
h2.start();
2、實(shí)現(xiàn)Runnable接口
- 優(yōu)點(diǎn):線程和線程執(zhí)行的任務(wù)分離
public class HandleMsg implements Runnable{private String threadKey;public HandleMsg(String threadKey){this.threadKey=threadKey;}@Overridepublic void run(){for(int i=0;i<10;i++){System.err.println(threadKey+":run");}}}
HandleMsg h1=new HandleMsg("h1");
HandleMsg h2=new HandleMsg("h2");
Thread t1=new Thread(h1);
Thread t2=new Thread(h2);
t1.start();
t2.start();
3、實(shí)現(xiàn)Callable接口
FutureTask implements RunnableFuture
,RunnableFuture<V> extends Runnable
- 優(yōu)點(diǎn)
- 線程和線程執(zhí)行的任務(wù)分離
- 有返回值
- 可以聲明拋出的異常
public class HandleMsg implements Callable<String>{private String threadKey;public HandleMsg(String threadKey){this.threadKey=threadKey;}@Overridepublic String call() throws Exception{for(int i=0;i<10;i++){System.err.println(threadKey+":run");}return threadKey;}}
HandleMsg h1=new HandleMsg("h1");
HandleMsg h2=new HandleMsg("h2");
FutureTask<String> f1=new FutureTask<>(h1);
FutureTask<String> f2=new FutureTask<>(h2);
Thread t1=new Thread(f1);
Thread t2=new Thread(f2);
t1.start();
t2.start();
String result1=f1.get();
String result2=f2.get();
三、API
1、獲取運(yùn)行使用的線程
Thread thread=Thread.currentThread();
2、唯一標(biāo)識(shí)
long getId();
3、線程名
String getName();
void setName(String name);
4、優(yōu)先級(jí)
- 線程有10個(gè)優(yōu)先級(jí),用1-10表示,默認(rèn)為5
int getPriority();
void setPriority(int newPriority);
5、是否處于活動(dòng)狀態(tài)
boolean isAlive();
6、守護(hù)線程
- 守護(hù)線程又稱為后臺(tái)線程,默認(rèn)創(chuàng)建出來的線程都是普通線程或稱為前臺(tái)線程
- 當(dāng)進(jìn)程結(jié)束時(shí),所有正在運(yùn)行的守護(hù)線程都會(huì)被強(qiáng)制中斷
- 進(jìn)程的結(jié)束:當(dāng)一個(gè)進(jìn)程中沒有任何前臺(tái)線程時(shí)即結(jié)束
- main主線程就是前臺(tái)線程,不受其他線程影響,分配其他線程后接著干自己的事,其他線程執(zhí)行的時(shí)候,main線程可能已經(jīng)結(jié)束了
boolean isDaemon();
void setDaemon(boolean on);
7、join
- 作用是:讓當(dāng)前執(zhí)行的線程陷入等待(內(nèi)部調(diào)用了wait方法)。
- 永久等待:其實(shí)現(xiàn)原理是不停的檢查當(dāng)前線程是否存活,該線程的任務(wù)執(zhí)行完畢后就會(huì)處于死亡狀態(tài),如果存活則說明任務(wù)還未執(zhí)行完畢-繼續(xù)等待
- 線程啟動(dòng)之后調(diào)用
1、API
void join();
void join(long millis);
2、有無join對(duì)比
Thread t1=new Thread(()->{for(int i=0;i<5;i++){System.err.println(i);}
});
t1.start();System.err.println("next task");
Thread t1=new Thread(()->{for(int i=0;i<5;i++){System.err.println(i);}
});
t1.start();t1.join();System.err.println("next task");
8、yield
- 線程讓步
- 暫停(不是終止)當(dāng)前正在執(zhí)行的線程任務(wù),讓其它具有相同優(yōu)先級(jí)或更高優(yōu)先級(jí)的等待的線程執(zhí)行任務(wù)(其它也會(huì)包含暫停的線程,所以有可能剛暫停就執(zhí)行)
- 暫停的線程狀態(tài)變化:運(yùn)行狀態(tài) -> 就緒狀態(tài)
- 暫停期間不會(huì)釋放鎖,所以其他線程獲取不到鎖
9、sleep
- 使線程睡眠
- sleep的睡眠期間不會(huì)釋放鎖,所以其它線程獲取不到鎖
- 睡眠線程的狀態(tài)變化:運(yùn)行狀態(tài) -> 阻塞狀態(tài) -> 就緒狀態(tài)
static void sleep(long millis) throws InterruptedException;
sleep | wait |
---|
屬于Thread類 | 屬于Object類 |
可以在任何地方使用 | wait、notify、notifyAll 只能在同步方法、同步控制塊里面使用 |
睡眠期間不會(huì)釋放鎖 | 會(huì)釋放鎖,而且會(huì)將當(dāng)前線程加入到等待隊(duì)列中 |
不需要喚醒 | 可以被notify、notifyAll喚醒 |
| |
10、線程中斷
- 只是打斷線程的睡眠,不會(huì)終止線程的繼續(xù)執(zhí)行
boolean isInterrupted();
Thread t1=new Thread(()->{System.err.println("run......");try{Thread.sleep(10000L);}catch(InterruptedException e){e.printStackTrace();}System.err.println("end......");
});
t1.start();
t1.interrupt();System.err.println("next task");