一、進(jìn)程和線(xiàn)程
進(jìn)程:進(jìn)程是具有一定獨(dú)立功能的程序關(guān)于某個(gè)數(shù)據(jù)集合上的一次運(yùn)行活動(dòng),進(jìn)程是系統(tǒng)進(jìn)行資源分配和調(diào)度的一個(gè)獨(dú)立單位.
線(xiàn)程:線(xiàn)程是進(jìn)程的一個(gè)實(shí)體,是CPU調(diào)度和分派的基本單位,它是比進(jìn)程更小的能獨(dú)立運(yùn)行的基本單位.線(xiàn)程自己基本上不擁有系統(tǒng)資源,只擁有一點(diǎn)在運(yùn)行中必不可少的資源(如程序計(jì)數(shù)器,一組寄存器和棧),但是它可與同屬一個(gè)進(jìn)程的其他的線(xiàn)程共享進(jìn)程所擁有的全部資源.
特點(diǎn)與區(qū)別:
1白群、簡(jiǎn)而言之,一個(gè)程序至少有一個(gè)進(jìn)程,一個(gè)進(jìn)程至少有一個(gè)線(xiàn)程.
2、線(xiàn)程的劃分尺度小于進(jìn)程妆棒,使得多線(xiàn)程程序的并發(fā)性高。
3沸伏、另外糕珊,進(jìn)程在執(zhí)行過(guò)程中擁有獨(dú)立的內(nèi)存單元,而多個(gè)線(xiàn)程共享內(nèi)存毅糟,從而極大地提高了程序的運(yùn)行效率红选。
4、線(xiàn)程在執(zhí)行過(guò)程中與進(jìn)程還是有區(qū)別的姆另。每個(gè)獨(dú)立的線(xiàn)程有一個(gè)程序運(yùn)行的入口喇肋、順序執(zhí)行序列和程序的出口。但是線(xiàn)程不能夠獨(dú)立執(zhí)行迹辐,必須依存在應(yīng)用程序中蝶防,由應(yīng)用程序提供多個(gè)線(xiàn)程執(zhí)行控制。
5明吩、從邏輯角度來(lái)看间学,多線(xiàn)程的意義在于一個(gè)應(yīng)用程序中,有多個(gè)執(zhí)行部分可以同時(shí)執(zhí)行印荔。但操作系統(tǒng)并沒(méi)有將多個(gè)線(xiàn)程看做多個(gè)獨(dú)立的應(yīng)用低葫,來(lái)實(shí)現(xiàn)進(jìn)程的調(diào)度和管理以及資源分配。這就是進(jìn)程和線(xiàn)程的重要區(qū)別仍律。
二嘿悬、線(xiàn)程的五大基本狀態(tài)及相互轉(zhuǎn)換
1.新建狀態(tài)(New):
當(dāng)用new操作符創(chuàng)建一個(gè)線(xiàn)程時(shí), 例如new Thread(r)水泉,線(xiàn)程還沒(méi)有開(kāi)始運(yùn)行善涨,此時(shí)線(xiàn)程處在新建狀態(tài)。 當(dāng)一個(gè)線(xiàn)程處于新生狀態(tài)時(shí)草则,程序還沒(méi)有開(kāi)始運(yùn)行線(xiàn)程中的代碼钢拧。
多線(xiàn)程的實(shí)現(xiàn)方法:a、繼承Thread類(lèi)畔师;b娶靡、實(shí)現(xiàn)Runnable接口
2.就緒狀態(tài)(Runnable)
一個(gè)新創(chuàng)建的線(xiàn)程并不自動(dòng)開(kāi)始運(yùn)行牧牢,要執(zhí)行線(xiàn)程看锉,必須調(diào)用線(xiàn)程的start()方法姿锭。當(dāng)線(xiàn)程對(duì)象調(diào)用start()方法即啟動(dòng)了線(xiàn)程,start()方法創(chuàng)建線(xiàn)程運(yùn)行的系統(tǒng)資源伯铣,并調(diào)度線(xiàn)程運(yùn)行run()方法呻此。當(dāng)start()方法返回后,線(xiàn)程就處于就緒狀態(tài)腔寡。
處于就緒狀態(tài)的線(xiàn)程并不一定立即運(yùn)行run()方法焚鲜,線(xiàn)程還必須同其他線(xiàn)程競(jìng)爭(zhēng)CPU時(shí)間,只有獲得CPU時(shí)間才可以運(yùn)行線(xiàn)程放前。因?yàn)樵趩蜟PU的計(jì)算機(jī)系統(tǒng)中忿磅,不可能同時(shí)運(yùn)行多個(gè)線(xiàn)程,一個(gè)時(shí)刻僅有一個(gè)線(xiàn)程處于運(yùn)行狀態(tài)凭语。因此此時(shí)可能有多個(gè)線(xiàn)程處于就緒狀態(tài)葱她。對(duì)多個(gè)處于就緒狀態(tài)的線(xiàn)程是由Java運(yùn)行時(shí)系統(tǒng)的線(xiàn)程調(diào)度程序(thread scheduler)來(lái)調(diào)度的。
3.運(yùn)行狀態(tài)(Running)
當(dāng)線(xiàn)程獲得CPU時(shí)間后似扔,它才進(jìn)入運(yùn)行狀態(tài)吨些,真正開(kāi)始執(zhí)行run()方法.
4. 阻塞狀態(tài)(Blocked)
線(xiàn)程運(yùn)行過(guò)程中,可能由于各種原因進(jìn)入阻塞狀態(tài):
1>線(xiàn)程通過(guò)調(diào)用sleep方法進(jìn)入睡眠狀態(tài)炒辉;sleep方法必須帶參數(shù)豪墅,sleep后可以用interrupt喚醒
2>線(xiàn)程調(diào)用一個(gè)在I/O上被阻塞的操作,即該操作在輸入輸出操作完成之前不會(huì)返回到它的調(diào)用者黔寇;
3>線(xiàn)程試圖得到一個(gè)鎖偶器,而該鎖正被其他線(xiàn)程持有;
4>線(xiàn)程在等待某個(gè)觸發(fā)條件缝裤;
......
所謂阻塞狀態(tài)是正在運(yùn)行的線(xiàn)程沒(méi)有運(yùn)行結(jié)束状囱,暫時(shí)讓出CPU,這時(shí)其他處于就緒狀態(tài)的線(xiàn)程就可以獲得CPU時(shí)間倘是,進(jìn)入運(yùn)行狀態(tài)亭枷。
join()方法:
當(dāng)A線(xiàn)程執(zhí)行到了B線(xiàn)程的.join()方法時(shí),A就會(huì)等待搀崭。等B線(xiàn)程都執(zhí)行完叨粘,A才會(huì)執(zhí)行。
join可以用來(lái)臨時(shí)加入線(xiàn)程執(zhí)行瘤睹。
1.線(xiàn)程使用join方法升敲,主線(xiàn)程就停下,等它執(zhí)行完轰传,那么如果該線(xiàn)程凍結(jié)了驴党,主線(xiàn)程就掛了,這也是為什么線(xiàn)程要拋異常的原因
2.當(dāng)兩個(gè)或以上線(xiàn)程開(kāi)啟了获茬,這個(gè)A線(xiàn)程才使用join方法港庄,那么主線(xiàn)程還是停下倔既,這幾個(gè)個(gè)線(xiàn)程交替進(jìn)行,直到A執(zhí)行完鹏氧,主線(xiàn)程才復(fù)活
sleep()和wait()方法:
a渤涌、(1)首先,調(diào)用sleep()之后把还,會(huì)引起當(dāng)前執(zhí)行的線(xiàn)程進(jìn)入暫時(shí)中斷狀態(tài)实蓬,也即睡眠狀態(tài)。
(2)其次吊履,雖然當(dāng)前線(xiàn)程進(jìn)入了睡眠狀態(tài)安皱,但是依然持有monitor對(duì)象。
(3)在中斷完成之后艇炎,自動(dòng)進(jìn)入喚醒狀態(tài)從而繼續(xù)執(zhí)行代碼练俐。
b、(1)首先冕臭,調(diào)用了wait()之后會(huì)引起當(dāng)前線(xiàn)程處于等待狀狀態(tài)腺晾。
(2)其次,每個(gè)線(xiàn)程必須持有該對(duì)象的monitor辜贵。如果在當(dāng)前線(xiàn)程中調(diào)用wait()方法之后悯蝉,該線(xiàn)程就會(huì)釋放monitor的持有對(duì)象并讓自己處于等待狀態(tài)。
(3)如果想喚醒一個(gè)正在等待的線(xiàn)程托慨,那么需要開(kāi)啟一個(gè)線(xiàn)程通過(guò)notify()或者notifyAll()方法去通知正在等待的線(xiàn)程獲取monitor對(duì)象鼻由。如此,該線(xiàn)程即可打破等待的狀態(tài)繼續(xù)執(zhí)行代碼厚棵。
5. 死亡狀態(tài)(Dead)
有兩個(gè)原因會(huì)導(dǎo)致線(xiàn)程死亡:
1) run方法正常退出而自然死亡蕉世,
2) 一個(gè)未捕獲的異常終止了run方法而使線(xiàn)程猝死。
為了確定線(xiàn)程在當(dāng)前是否存活著(就是要么是可運(yùn)行的婆硬,要么是被阻塞了)狠轻,需要使用isAlive方法。如果是可運(yùn)行或被阻塞彬犯,這個(gè)方法返回true向楼; 如果線(xiàn)程仍舊是new狀態(tài)且不是可運(yùn)行的, 或者線(xiàn)程死亡了谐区,則返回false.
三湖蜕、線(xiàn)程安全和線(xiàn)程同步
線(xiàn)程安全就是多線(xiàn)程訪(fǎng)問(wèn)時(shí),采用了加鎖機(jī)制宋列,當(dāng)一個(gè)線(xiàn)程訪(fǎng)問(wèn)該類(lèi)的某個(gè)數(shù)據(jù)時(shí)昭抒,進(jìn)行保護(hù),其他線(xiàn)程不能進(jìn)行訪(fǎng)問(wèn)直到該線(xiàn)程讀取完,其他線(xiàn)程才可使用灭返。不會(huì)出現(xiàn)數(shù)據(jù)不一致或者數(shù)據(jù)污染盗迟。
線(xiàn)程不安全就是不提供數(shù)據(jù)訪(fǎng)問(wèn)保護(hù),有可能出現(xiàn)多個(gè)線(xiàn)程先后更改數(shù)據(jù)造成所得到的數(shù)據(jù)是臟數(shù)據(jù)婆殿。
補(bǔ)充:
線(xiàn)程類(lèi)的一些常用方法:
sleep(): 強(qiáng)迫一個(gè)線(xiàn)程睡眠N毫秒。
isAlive(): 判斷一個(gè)線(xiàn)程是否存活罩扇。
join(): 等待線(xiàn)程終止婆芦。
activeCount(): 程序中活躍的線(xiàn)程數(shù)。
enumerate(): 枚舉程序中的線(xiàn)程喂饥。
currentThread(): 得到當(dāng)前線(xiàn)程消约。
isDaemon(): 一個(gè)線(xiàn)程是否為守護(hù)線(xiàn)程。
setDaemon(): 設(shè)置一個(gè)線(xiàn)程為守護(hù)線(xiàn)程员帮。(用戶(hù)線(xiàn)程和守護(hù)線(xiàn)程的區(qū)別在于或粮,是否等待主線(xiàn)程依賴(lài)于主線(xiàn)程結(jié)束而結(jié)束)
setName(): 為線(xiàn)程設(shè)置一個(gè)名稱(chēng)。
wait(): 強(qiáng)迫一個(gè)線(xiàn)程等待捞高。
notify(): 通知一個(gè)線(xiàn)程繼續(xù)運(yùn)行氯材。
setPriority(): 設(shè)置一個(gè)線(xiàn)程的優(yōu)先級(jí)。