更新時(shí)間:2021-02-02 17:22:49 來(lái)源:動(dòng)力節(jié)點(diǎn) 瀏覽1513次
線(xiàn)程(thread)是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位,也是獨(dú)立調(diào)度和分派的基本單位。線(xiàn)程作為計(jì)算機(jī)技術(shù)中十分重要的內(nèi)容,線(xiàn)程是我們必須要掌握的重點(diǎn)知識(shí)。在線(xiàn)程中的許多操作,比如終止線(xiàn)程都是需要調(diào)用線(xiàn)程操作方法來(lái)實(shí)現(xiàn)的,本文我們通過(guò)一些實(shí)例來(lái)介紹這些線(xiàn)程操作方法。
我們比較熟悉的一些線(xiàn)程操作方法:
Thread.currentThread().getName();獲取當(dāng)前運(yùn)行線(xiàn)程的名字
suspend:暫停線(xiàn)程后不釋放鎖,容易造成死鎖
stop:線(xiàn)程被粗暴終結(jié),的資源不能釋放
interrupt:通知線(xiàn)程可以結(jié)束,線(xiàn)程可以完全不理會(huì), 結(jié)合isInterrupted使用
注意interrupted方法和isInterrupted的區(qū)別,前者會(huì)在調(diào)用后清除interrupted status,后者不會(huì)。
中斷線(xiàn)程不建議自主設(shè)置標(biāo)志位,因?yàn)槿绻峭ㄟ^(guò)判斷標(biāo)志位進(jìn)入線(xiàn)程sleep、wait、take等方法,線(xiàn)程被阻塞,就不會(huì)再判斷標(biāo)志位,而使用interrupt就不會(huì)產(chǎn)生這樣的問(wèn)題,因?yàn)樗麄兛梢宰詣?dòng)監(jiān)控線(xiàn)程中斷狀態(tài)。(如果是在runnable中想使用這個(gè)方法,就使用Thread.currentThread.isInterrupted即可)
使用interrupt中斷線(xiàn)程
public class HasInterruptException extends Thread {
????@Override
????public void run() {
????????super.run();
????????while (!isInterrupted()) {
????????????System.out.println(Thread.currentThread().getName() + "is running");
????????}
????????System.out.println(Thread.currentThread().getName() + "interrupt flag is " + isInterrupted());
????}
????public static void main(String[] args) {
????????HasInterruptException hasInterruptException = new HasInterruptException();
????????hasInterruptException.start();
????????try {
????????????Thread.sleep(400);
????????} catch (InterruptedException e) {
????????????e.printStackTrace();
????????}
????????hasInterruptException.interrupt();
????}
}
線(xiàn)程阻塞方法也可以監(jiān)控線(xiàn)程interrput方法,如果處于阻塞狀態(tài),會(huì)被程序檢測(cè)出來(lái),并拋出interruptedException異常,同時(shí)將interrupt狀態(tài)恢復(fù),但線(xiàn)程會(huì)繼續(xù)運(yùn)行剩余的任務(wù)
public class HasInterruptException extends Thread {
????@Override
????public void run() {
????????super.run();
????????while (!isInterrupted()) {
????????????try {
????????????????sleep(500);
????????????} catch (InterruptedException e) {
????????????????e.printStackTrace();
????????????}
????????????System.out.println(Thread.currentThread().getName() + "is running");
????????????System.out.println(Thread.currentThread().getName() + "now interrupt state " + isInterrupted());
????????}
????????System.out.println(Thread.currentThread().getName() + "interrupt flag is " + isInterrupted());
????}
????public static void main(String[] args) {
????????HasInterruptException hasInterruptException = new HasInterruptException();
????????hasInterruptException.start();
????????try {
????????????Thread.sleep(400);
????????} catch (InterruptedException e) {
????????????e.printStackTrace();
????????}
????????hasInterruptException.interrupt();
????}
}
如果需要在有阻塞代碼時(shí)也能正常中斷線(xiàn)程,需要在阻塞方法檢查到中斷時(shí)再添加中斷方法,在interrupt()之前可以添加一些善后處理代碼
?@Override
????public void run() {
????????super.run();
????????while (!isInterrupted()) {
????????????try {
????????????????sleep(500);
????????????} catch (InterruptedException e) {
????????????????e.printStackTrace();
????????????????//如果需要在有阻塞代碼時(shí)也能正常中斷線(xiàn)程,需要在阻塞方法檢查到中斷時(shí)再添加中斷方法,在此之前可以添加一些善后處理代碼
????????????????interrupt();
????????????}
????????????System.out.println(Thread.currentThread().getName() + "is running");
????????????System.out.println(Thread.currentThread().getName() + "now interrupt state " + isInterrupted());
????????}
????????System.out.println(Thread.currentThread().getName() + "interrupt flag is " + isInterrupted());
????}
由此可知,阻塞方法中檢測(cè)到中斷會(huì)拋出異常到原因是為了提示程序這時(shí)候線(xiàn)程不能直接中斷,需要正確處理善后,再執(zhí)行中斷。
start:Thread僅僅是一個(gè)線(xiàn)程相關(guān)類(lèi),new出來(lái)后不調(diào)用start方法是沒(méi)有開(kāi)啟線(xiàn)程的。
start方法只能調(diào)用一次,多次調(diào)用會(huì)拋出IllegalThreadStateException異常
如果new一個(gè)Thread之后直接調(diào)用run方法,和調(diào)用一個(gè)普通方法效果完全一致,在主線(xiàn)程中執(zhí)行。
yield:執(zhí)行該方法的線(xiàn)程會(huì)讓出cpu的執(zhí)行權(quán),進(jìn)入就緒狀態(tài)。不會(huì)釋放鎖,調(diào)用該方法后cpu可能還會(huì)重新選中該線(xiàn)程執(zhí)行,所以這個(gè)方法不可靠。
join:讓調(diào)用該方法的線(xiàn)程執(zhí)行完畢之后,其他線(xiàn)程才能執(zhí)行,必須放在start之后。有三個(gè)重載方法,參考 Java Thread的join() 之刨根問(wèn)底
static class A extends Thread {
????????@Override
????????public void run() {
????????????super.run();
????????????try {
????????????????Thread.sleep(2000);
????????????} catch (InterruptedException e) {
????????????????e.printStackTrace();
????????????}
????????????System.out.println(Thread.currentThread().getName() + " runing end");
????????}
????}
????public static void main(String[] args) {
????????A a = new A();
????????A aa = new A();
????????a.start();
????????aa.start();
????????try {
????????????aa.join();
????????} catch (InterruptedException e) {
????????????e.printStackTrace();
????????}
????}
setPriority:設(shè)置線(xiàn)程優(yōu)先級(jí),這個(gè)方法不完全可靠,也有一定效果
setDaemon(boolean)守護(hù)線(xiàn)程,當(dāng)進(jìn)程中所有線(xiàn)程都是守護(hù)線(xiàn)程時(shí)候,進(jìn)程結(jié)束
守護(hù)線(xiàn)程因?yàn)橛脩?hù)線(xiàn)程結(jié)束而被動(dòng)結(jié)束時(shí)候,線(xiàn)程中的方法不一定能完全執(zhí)行,如finally語(yǔ)句不一定能執(zhí)行
notify()/notifyAll() 不會(huì)釋放鎖
注: wait(),notify(),notifyAll()應(yīng)該放在synchronized關(guān)鍵字所保護(hù)的內(nèi)容內(nèi),wait方法調(diào)用時(shí)調(diào)用方釋放鎖,但是notify/notifyAll調(diào)用時(shí)調(diào)用方需要在線(xiàn)程方法運(yùn)行完畢之后才釋放鎖,所以notify/notifyAll一般會(huì)被放在同步代碼塊的最后一行。
wait() wait是指在一個(gè)已經(jīng)進(jìn)入了同步鎖的線(xiàn)程內(nèi),讓自己暫時(shí)讓出同步鎖,以便其他正在等待此鎖的線(xiàn)程可以得到同步鎖并運(yùn)行,只有其他線(xiàn)程調(diào)用了notify方法(notify并不釋放鎖,只是告訴調(diào)用過(guò)wait方法的線(xiàn)程可以去參與獲得鎖的競(jìng)爭(zhēng)了,但不是馬上得到鎖,因?yàn)殒i還在別人手里,別人還沒(méi)釋放。如果notify方法后面的代碼還有很多,需要這些代碼執(zhí)行完后才會(huì)釋放鎖,可以在notfiy方法后增加一個(gè)等待和一些代碼),調(diào)用wait方法的線(xiàn)程就會(huì)解除wait狀態(tài)并爭(zhēng)搶cpu使用權(quán),搶到了之后才會(huì)執(zhí)行wait之后的代碼??梢灾付ㄍV沟臅r(shí)間參數(shù),也可不指定。
sleep() sleep就是正在執(zhí)行的線(xiàn)程主動(dòng)讓出cpu,cpu去執(zhí)行其他線(xiàn)程,在sleep指定的時(shí)間過(guò)后,cpu才會(huì)回到這個(gè)線(xiàn)程上繼續(xù)往下執(zhí)行,如果當(dāng)前線(xiàn)程進(jìn)入了同步鎖,sleep方法并不會(huì)釋放鎖,即使當(dāng)前線(xiàn)程使用sleep方法讓出了cpu,但其他被同步鎖擋住了的線(xiàn)程也無(wú)法得到執(zhí)行。當(dāng)休眠時(shí)間到并跑完同步代碼之后才會(huì)釋放鎖。和wait一樣,調(diào)用時(shí)候都會(huì)把cpu資源讓出。
注:obj=null 只是表示這個(gè)引用不再指向該對(duì)象,不代表這個(gè)對(duì)象不存在了
?????PDD pp = new PDD();
????????PDD ppp = pp;
????????System.out.println(pp);
????????System.out.println(ppp);
????????pp = null;
????????System.out.println(pp);
????????System.out.println(ppp);
????????輸出
????????//com.example.annotation.PDD@6d06d69c
????????//com.example.annotation.PDD@6d06d69c
????????//null
????????//com.example.annotation.PDD@6d06d69c
想讓對(duì)象被垃圾回收機(jī)制回收,需要保證沒(méi)有強(qiáng)引用指向這個(gè)對(duì)象
注:線(xiàn)程同步阻塞的一個(gè)例子
@Override
????public void run() {
????????while (!Thread.currentThread().isInterrupted()) {
????????????System.out.println(Thread.currentThread().getName() + " start");
????????????synchronized (this) {
????????????????try {
????????????????????System.out.println(Thread.currentThread().getName() + "sleep start");
????????????????????Thread.sleep(5000);
????????????????} catch (InterruptedException e) {
????????????????????e.printStackTrace();
????????????????}
????????????????System.out.println(Thread.currentThread().getName() + "sleep end");
????????????}
????????????System.out.println(Thread.currentThread().getName() + " continue...");
????????}
????}
所有遇到同步代碼塊或者同步方法的線(xiàn)程都會(huì)被阻塞,除非搶到鎖,搶到鎖之后會(huì)繼續(xù)往下執(zhí)行,而不會(huì)跳過(guò)同步代碼塊/同步方法再執(zhí)行。
以上就是一些線(xiàn)程操作方法的實(shí)例講解,線(xiàn)程操作方法的掌握不僅僅是用來(lái)實(shí)現(xiàn)線(xiàn)程的各種操作,對(duì)于我們加深理解線(xiàn)程的工作原理和線(xiàn)程中的各種機(jī)制也有很大的幫助。在本站的多線(xiàn)程教程中,對(duì)線(xiàn)程的操作方法還有更多的解讀和介紹,感興趣想要在多線(xiàn)程領(lǐng)域?qū)W有所成的小伙伴不要錯(cuò)過(guò)哦。
Java實(shí)驗(yàn)班
0基礎(chǔ) 0學(xué)費(fèi) 15天面授
Java就業(yè)班
有基礎(chǔ) 直達(dá)就業(yè)
Java夜校直播班
業(yè)余時(shí)間 高薪轉(zhuǎn)行
Java在職加薪班
工作1~3年,加薪神器
Java架構(gòu)師班
工作3~5年,晉升架構(gòu)
提交申請(qǐng)后,顧問(wèn)老師會(huì)電話(huà)與您溝通安排學(xué)習(xí)