更新時(shí)間:2021-02-02 17:22:49 來源:動(dòng)力節(jié)點(diǎn) 瀏覽1307次
線程(thread)是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位,也是獨(dú)立調(diào)度和分派的基本單位。線程作為計(jì)算機(jī)技術(shù)中十分重要的內(nèi)容,線程是我們必須要掌握的重點(diǎn)知識。在線程中的許多操作,比如終止線程都是需要調(diào)用線程操作方法來實(shí)現(xiàn)的,本文我們通過一些實(shí)例來介紹這些線程操作方法。
我們比較熟悉的一些線程操作方法:
Thread.currentThread().getName();獲取當(dāng)前運(yùn)行線程的名字
suspend:暫停線程后不釋放鎖,容易造成死鎖
stop:線程被粗暴終結(jié),的資源不能釋放
interrupt:通知線程可以結(jié)束,線程可以完全不理會(huì), 結(jié)合isInterrupted使用
注意interrupted方法和isInterrupted的區(qū)別,前者會(huì)在調(diào)用后清除interrupted status,后者不會(huì)。
中斷線程不建議自主設(shè)置標(biāo)志位,因?yàn)槿绻峭ㄟ^判斷標(biāo)志位進(jìn)入線程sleep、wait、take等方法,線程被阻塞,就不會(huì)再判斷標(biāo)志位,而使用interrupt就不會(huì)產(chǎn)生這樣的問題,因?yàn)樗麄兛梢宰詣?dòng)監(jiān)控線程中斷狀態(tài)。(如果是在runnable中想使用這個(gè)方法,就使用Thread.currentThread.isInterrupted即可)
使用interrupt中斷線程
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();
????}
}
線程阻塞方法也可以監(jiān)控線程interrput方法,如果處于阻塞狀態(tài),會(huì)被程序檢測出來,并拋出interruptedException異常,同時(shí)將interrupt狀態(tài)恢復(fù),但線程會(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í)也能正常中斷線程,需要在阻塞方法檢查到中斷時(shí)再添加中斷方法,在interrupt()之前可以添加一些善后處理代碼
?@Override
????public void run() {
????????super.run();
????????while (!isInterrupted()) {
????????????try {
????????????????sleep(500);
????????????} catch (InterruptedException e) {
????????????????e.printStackTrace();
????????????????//如果需要在有阻塞代碼時(shí)也能正常中斷線程,需要在阻塞方法檢查到中斷時(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());
????}
由此可知,阻塞方法中檢測到中斷會(huì)拋出異常到原因是為了提示程序這時(shí)候線程不能直接中斷,需要正確處理善后,再執(zhí)行中斷。
start:Thread僅僅是一個(gè)線程相關(guān)類,new出來后不調(diào)用start方法是沒有開啟線程的。
start方法只能調(diào)用一次,多次調(diào)用會(huì)拋出IllegalThreadStateException異常
如果new一個(gè)Thread之后直接調(diào)用run方法,和調(diào)用一個(gè)普通方法效果完全一致,在主線程中執(zhí)行。
yield:執(zhí)行該方法的線程會(huì)讓出cpu的執(zhí)行權(quán),進(jìn)入就緒狀態(tài)。不會(huì)釋放鎖,調(diào)用該方法后cpu可能還會(huì)重新選中該線程執(zhí)行,所以這個(gè)方法不可靠。
join:讓調(diào)用該方法的線程執(zhí)行完畢之后,其他線程才能執(zhí)行,必須放在start之后。有三個(gè)重載方法,參考 Java Thread的join() 之刨根問底
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è)置線程優(yōu)先級,這個(gè)方法不完全可靠,也有一定效果
setDaemon(boolean)守護(hù)線程,當(dāng)進(jìn)程中所有線程都是守護(hù)線程時(shí)候,進(jìn)程結(jié)束
守護(hù)線程因?yàn)橛脩艟€程結(jié)束而被動(dòng)結(jié)束時(shí)候,線程中的方法不一定能完全執(zhí)行,如finally語句不一定能執(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)用方需要在線程方法運(yùn)行完畢之后才釋放鎖,所以notify/notifyAll一般會(huì)被放在同步代碼塊的最后一行。
wait() wait是指在一個(gè)已經(jīng)進(jìn)入了同步鎖的線程內(nèi),讓自己暫時(shí)讓出同步鎖,以便其他正在等待此鎖的線程可以得到同步鎖并運(yùn)行,只有其他線程調(diào)用了notify方法(notify并不釋放鎖,只是告訴調(diào)用過wait方法的線程可以去參與獲得鎖的競爭了,但不是馬上得到鎖,因?yàn)殒i還在別人手里,別人還沒釋放。如果notify方法后面的代碼還有很多,需要這些代碼執(zhí)行完后才會(huì)釋放鎖,可以在notfiy方法后增加一個(gè)等待和一些代碼),調(diào)用wait方法的線程就會(huì)解除wait狀態(tài)并爭搶cpu使用權(quán),搶到了之后才會(huì)執(zhí)行wait之后的代碼。可以指定停止的時(shí)間參數(shù),也可不指定。
sleep() sleep就是正在執(zhí)行的線程主動(dòng)讓出cpu,cpu去執(zhí)行其他線程,在sleep指定的時(shí)間過后,cpu才會(huì)回到這個(gè)線程上繼續(xù)往下執(zhí)行,如果當(dāng)前線程進(jìn)入了同步鎖,sleep方法并不會(huì)釋放鎖,即使當(dāng)前線程使用sleep方法讓出了cpu,但其他被同步鎖擋住了的線程也無法得到執(zhí)行。當(dāng)休眠時(shí)間到并跑完同步代碼之后才會(huì)釋放鎖。和wait一樣,調(diào)用時(shí)候都會(huì)把cpu資源讓出。
注:obj=null 只是表示這個(gè)引用不再指向該對象,不代表這個(gè)對象不存在了
?????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
想讓對象被垃圾回收機(jī)制回收,需要保證沒有強(qiáng)引用指向這個(gè)對象
注:線程同步阻塞的一個(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...");
????????}
????}
所有遇到同步代碼塊或者同步方法的線程都會(huì)被阻塞,除非搶到鎖,搶到鎖之后會(huì)繼續(xù)往下執(zhí)行,而不會(huì)跳過同步代碼塊/同步方法再執(zhí)行。
以上就是一些線程操作方法的實(shí)例講解,線程操作方法的掌握不僅僅是用來實(shí)現(xiàn)線程的各種操作,對于我們加深理解線程的工作原理和線程中的各種機(jī)制也有很大的幫助。在本站的多線程教程中,對線程的操作方法還有更多的解讀和介紹,感興趣想要在多線程領(lǐng)域?qū)W有所成的小伙伴不要錯(cuò)過哦。
初級 202925
初級 203221
初級 202629
初級 203743