網(wǎng)上很多資料對多線程都有詳細的描述與理解,本菜鳥剛剛?cè)腴TJAVA對多線程方面不是很熟悉政模,在看過很多視屏岗宣,以及相關(guān)博客,書籍通過自己的語言來描述對JAVA多線程的理解淋样,給一些和我一樣的菜鳥一起交流耗式,寫的不好的地方請各位大神多多指正,互相學(xué)習(xí)趁猴,共同進步刊咳。
1.什么是多線程?
是指一個應(yīng)用程序同時執(zhí)行多個任務(wù)躲叼,一般來說一個任務(wù)就是一個線程 ,而一個應(yīng)用程序有一個以上的線程我們稱之為多線程企巢。
2.什么是進程枫慷?
進程是一個正在執(zhí)行的程序 ,比如QQ浪规,迅雷等 一個進程的運行會向CPU申請在內(nèi)存中開辟一個內(nèi)存塊或听。
他是向CPU申請資源的,進程之間數(shù)據(jù)相互獨立笋婿,一個進程至少有一個線程誉裆。
3.什么是線程?
線程是進程中的單一的順序控制流程也可以叫做最小控制單元缸濒,線程是進程中執(zhí)行單元足丢,開啟一個線程比開啟一個進程更加節(jié)省資源。
4.多線程與多進程的區(qū)別庇配?
多進程擁有自己的一套數(shù)據(jù)變量斩跌,而多線程是共享數(shù)據(jù),而共享數(shù)據(jù)也會帶來一系列的安全問題(安全問題稍后再提)捞慌。
當(dāng)然在這里既然說到多線程肯定要提出多線程中線程的七大狀態(tài)
5.新建狀態(tài):
新建狀態(tài)也就是我們所說的創(chuàng)建狀態(tài)如 new Thread(r); 這個線程還沒有運行耀鸦,當(dāng)一個線程還是新建狀態(tài)的時候,程序還沒有開始運行線程中的代碼啸澡。
6.可運行狀態(tài)(就緒狀態(tài)):
一旦調(diào)用了Start()方法 那么線程就處與可以運行的狀態(tài)袖订,但是不是說這個線程會馬上開始執(zhí)行氮帐,而是根據(jù)操作系統(tǒng)來決定賦予它執(zhí)行的權(quán)力,但是也不是說這個線程拿到執(zhí)行的權(quán)力就一直會執(zhí)行洛姑,在線程運行中可能線程會中斷上沐,從而將執(zhí)行權(quán)力交給其他線程執(zhí)行。采用的是搶占方式調(diào)度吏口,給每一個線程一個時間片來執(zhí)行任務(wù)奄容,當(dāng)時間片(所謂的時間片就是一定的時間內(nèi),只執(zhí)行這個線程)時間到了产徊,操作系統(tǒng)會根據(jù)其他線程的優(yōu)先級(什么是線程的優(yōu)先級我們后面會講到)來賦予其他線程執(zhí)行權(quán)力昂勒。
7.運行狀態(tài):當(dāng)獲取到CPU執(zhí)行權(quán)力 開始正真的執(zhí)行Run方法中的代碼,這是運行狀態(tài)舟铜。
**8.阻塞狀態(tài): **
什么是阻塞狀態(tài)呢戈盈?,是指當(dāng)一個線程想獲取自己的一個內(nèi)置的對象鎖的時候谆刨,這個對象鎖被其他線程所占用塘娶,該線程不能執(zhí)行這個就是阻塞狀態(tài),除非當(dāng)另外一個線程釋放鎖痊夭,并且操作系統(tǒng)允許它執(zhí)行他才變?yōu)榉亲枞麪顟B(tài)刁岸。這個怎么理解呢其實鎖是分為對象鎖和類鎖 每一個對象都有一個內(nèi)置的鎖 ,在遇到同步的方法或則同步塊也就是 被Synchronized修飾的方法 或則使用synchronized的同步塊她我,那么如果一個繼承了Thread類或則實現(xiàn)了 Runnable接口的類 下面我們創(chuàng)建了兩個線程 這兩個線程是實例了相同類創(chuàng)建不同的兩個對象虹曙,分別啟動了開啟線程方法start(),因為我們在run方法中加了同步塊番舆,而同步塊的鎖是這個類的類鎖酝碳,所以只要是這個類的實例對象都可以得到這個鎖,但是我們都知道類鎖只有一把恨狈,那個線程先搶到疏哗,誰就擁有執(zhí)行權(quán)力,等到這個線程執(zhí)行完了禾怠,釋放鎖其他線程才能執(zhí)行返奉。 而沒有得到鎖的線程他的狀態(tài)就是阻塞狀態(tài),等到拿到鎖的線程執(zhí)行完了吗氏,再把鎖給它衡瓶,它就是非阻塞狀態(tài)了
public class ThreadTest extends Thread {
//標(biāo)記線程號
private int threadNo;
//生成構(gòu)造方法
public ThreadTest(int threadNo) {
this.threadNo = threadNo;
}
@Override
//同步方法默認同步對象
public void run() {
//可以把同步方法想成一個房屋,而同步代碼塊就是里面的保險箱 這個保險箱的鑰匙可以是 這個房間的鑰匙也可以是其他鑰匙
//我們在這里加了一個類鎖 ThreadTest.class 意思就是想進代碼塊必須是這個類是實例 但是類鎖只有一個 所以造成了兩個同步
// 每一個對象都有一個內(nèi)置的鎖 但是兩個一個類的實例同時訪問 這個類中的同步方法不會 同步牲证,除非采用synchronized(){}代碼塊給類加鎖
//因為我們創(chuàng)建的兩個對象是有兩把鎖哮针,每個對象一個 互相不干擾,除非給這個類加鎖
synchronized(ThreadTest.class){
for (int i = 1; i < 10; i++) {
System.out.println(“第” + threadNo + “是” + i);
}
}
}
public static void main(String[] args) throws InterruptedException {
//開啟兩個線程同時執(zhí)行
new ThreadTest(1).start();
new ThreadTest(2).start();
}
}
運行結(jié)果:
第1個是1
第1個是2
第1個是3
第1個是4
第1個是5
第1個是6
第1個是7
第1個是8
第1個是9
第2個是1
第2個是2
第2個是3
第2個是4
第2個是5
第2個是6
第2個是7
第2個是8
第2個是9
在這里看出兩個線程是同步的
9.等待狀態(tài):
在調(diào)用Object.wait線程進入等待狀態(tài),這個等待狀態(tài)必須是持有對象鎖也就是進入同步方法或則同步塊中調(diào)用不然會拋出IllegalMonitorStateException異常 這個方法如果被調(diào)用那么這個線程會自動釋放對象鎖并進入等待狀態(tài)十厢,除非有另外一個線程(持有對象鎖)的線程等太,也就是說他在執(zhí)行同步方法或則同步塊代碼中才能調(diào)用notify()或者notifyAll喚醒所有線程,那么該等待線程被喚醒并擁有可運行權(quán)力蛮放,并不是被喚醒就會得到對象鎖馬上運行缩抡,還是得看CPU老大給不給這個權(quán)力。
10.計時等待狀態(tài):
下面我們來說說計時等待狀態(tài)包颁,在很多面試題中都會有Object.wait和Thread.sleep方法有什么區(qū)別瞻想,其實在調(diào)用wait方法的時候進入等待狀態(tài)線程沒有執(zhí)行權(quán)力,但是調(diào)用Sleep方法該方法接受一個毫秒數(shù)娩嚼,這個單詞翻譯過來也就是休眠,可以這個樣子說蘑险,一個線程在調(diào)用這個sleep方法后進行等待,但是他不會釋放這個對象鎖岳悟,也就是說要拿到這個對象鎖的線程還是在 阻塞狀態(tài)佃迄,但是不進入這個同步方法也就是不需要這個對象鎖的線程還是可以繼續(xù)執(zhí)行,當(dāng)休眠時間一到贵少,馬上繼續(xù)執(zhí)行 這個就是wait和sleep的區(qū)別 一個是放棄鎖并進入等待呵俏,一個是不放棄鎖,時間到了就開始執(zhí)行滔灶,調(diào)用sleep()方法的線程狀態(tài)也就是計時等待狀態(tài)普碎。
11.掛起狀態(tài):
掛起狀態(tài)也叫做死亡狀態(tài),這種狀態(tài)是指線程在執(zhí)行完Run()方法中的代碼 正常結(jié)束或則沒有捕獲異常(也就是發(fā)生異常了沒有處理)而造成的線程結(jié)束录平÷槌担或則調(diào)用Stop()方法來殺死該線程不過Stop方法已經(jīng)過時,而且不推薦使用萄涯。