廖雪峯Java11多線程編程-1線程的概念-3線程的狀態

1線程的狀態

<img src="https://img2018.cnblogs.com/blog/1418970/201906/1418970-20190609155854030-1712068336.png" width="500" /> 線程終止的的緣由: * run()或call()方法執行完成,線程正常結束 * 線程拋出一個未捕獲的Exception或Error * 直接調用該線程的stop()方法來結束該線程——該方法容易致使死鎖,一般不推薦使用java

1.1對已經死亡的線程調用start()方法使他從新啓動,會引起IllegalThreadStateException

class MyThread extends Thread{
    public void run(){
        System.out.println("子線程");
    }
}
public class StartDead {
    public static void main(String[] args) throws InterruptedException{
        Thread t = new MyThread();
        t.start();
        while(t.isAlive()){
            Thread.sleep(200);
        }
        System.out.println(t.isAlive());
        t.start();
    }
}

<img src="https://img2018.cnblogs.com/blog/1418970/201906/1418970-20190609163317891-1856666325.png" width="500" />ide

2 控制線程

2.1 join線程

Thread提供了讓一個線程等待另外一個線程完成的方法——join()方法。this

  • join():等待該線程執行結束,再向下執行
  • join(long mills):等待被join的線程mills毫秒,超時再也不等待
  • join(long mills, int nanos):等待最長時間爲mills毫秒+nanos毫微秒,不多用
class MyThread extends Thread{
    String name;
    public MyThread(String name){
        this.name = name;
    }
    @Override
    public void run(){
        System.out.println("Hello, "+name+"!");
        try{
            Thread.sleep(2000);
        }catch (InterruptedException ex){
            ex.printStackTrace();
        }finally {
            System.out.println("Bye,"+name+"!");
        }
    }
}
public class StartDead {
    public static void main(String[] args) throws InterruptedException{
        Thread t1 = new MyThread("Bob");
        System.out.println("start");
        t1.start();
        t1.join(1000,10);
        System.out.println("end");
    }
}

<img src="https://img2018.cnblogs.com/blog/1418970/201906/1418970-20190609165330513-1373973209.png" width="500" />spa

2.2後臺線程

<font color=#FF0000>Java的程序入口就是JVM啓動main線程,main線程又能夠啓動其餘線程。當全部的線程都運行結束時,JVM退出。 有一種線程是無限循環,如定時任務。若是這種線程不結束,JVM就不能退出。 問題:由誰來結束這些線程?</font> 有一種線程,他是在後臺運行的,它的任務是爲其餘的線程提供服務,這種線程被成爲「後臺線程(Daemon Thread)」,又稱爲「守護線程」或「精靈線程」。JVM的垃圾回收線程就是典型的後臺線程。 總之:線程

  • 守護線程爲其餘線程服務的線程
  • 全部非守護線程都執行關閉後,虛擬機退出

特徵:code

  • 若是全部的前臺線程都死亡,後臺線程會自動死亡。
  • 不能持有資源(如打開文件等)當虛擬機退出時,守護線程沒有任何機會關閉文件,會致使數據丟失。

建立守護線程:調用Thread的對象的setDaemon(true)方法能夠將指定線程設置爲後臺線程。orm

public class DaemonThread extends Thread{
    public void run(){
        while(true){
            System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));
            try{
                Thread.sleep(1000);
            }catch (InterruptedException e){
                break;
            }

        }
    }
    public static void main(String[] args) throws InterruptedException{
        System.out.println("Main start");
        DaemonThread t = new DaemonThread();
        t.setDaemon(true);
        t.start();
        Thread.sleep(5000);
        System.out.println("Main end");
    }
}

<img src="https://img2018.cnblogs.com/blog/1418970/201906/1418970-20190609205707100-1404414409.png" width="500" />對象

package com.csj2018.lxf;

import org.junit.Ignore;
import org.junit.Test;

class DaemonThread extends Thread{
	public void run() {
		for(int i=0;i<1000;i++) {
			System.out.println(Thread.currentThread().getName()+"\t"+i);
			try {
				Thread.sleep(1000);
			}catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

public class ThreadTest2{
	@Test
	public void test() {
		Thread t = new DaemonThread();
		t.setDaemon(true);//setDaemon(true)必須在start()方法以前調用,不然會引起IllegalThreadStatsException
		t.start();
		for(int i=0;i<3;i++) {
			System.out.println(Thread.currentThread().getName()+"\t"+i);
			try {
				Thread.sleep(1000);
			}catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

<img src="https://img2018.cnblogs.com/blog/1418970/202002/1418970-20200202004852612-114306420.png" width="500" />blog

2.3線程睡眠

若是須要讓正在執行的線程暫停一段時間,並進入阻塞狀態,能夠調用Thread類的靜態方法sleep實現。當前線程調用sleep進入阻塞狀態後,在其睡眠時間內,該線程不會得到執行的機會,即便系統中沒有其餘可執行的線程,處於sleep中的線程,依然不會執行。所以sleep經常使用於程序的執行。資源

  • static void sleep(long mills):讓當前正在執行的線程暫停mills毫秒,並進入阻塞狀態
  • static void sleep(long mills, int nanos):讓當前正在執行的線程暫停mills毫秒+nanos毫微秒,並進入阻塞狀態,第二種不多用
import java.util.Date;

public class SleepTest extends Thread {
    public static void main(String[] args) throws InterruptedException{
        for(int i=0;i<10;i++){
            System.out.println("當前時間:"+new Date());
            Thread.sleep(1000);
        }
    }
}

<img src="https://img2018.cnblogs.com/blog/1418970/201906/1418970-20190609173630860-1274522324.png" width="500" /> ### 2.4線程讓步: yield yield讓當前正在執行的線程暫停,但不會阻塞該線程,它只是將該線程轉入就緒狀態。yield()只是讓當前線程暫停一下,讓系統的線程調度器從新調度一次,徹底可能的狀況:某個線程調用yield方法暫停後,線程調度器又將其調度出來從新執行。 當某個線程用了yield方法暫停以後,只有優先級與當前線程相同,或者優先級比當前線程更高處於就緒狀態的線程纔會得到執行的機會。 ```#java public class YieldTest extends Thread{ public YieldTest(String name){ super(name); } public void run(){ for(int i=0;i<10;i++){ System.out.println(Thread.currentThread().getName()+" "+i); if(i==5){ Thread.yield(); } } } public static void main(String[] args) throws InterruptedException{ YieldTest yt1 = new YieldTest("高級"); yt1.setPriority(Thread.MAX_PRIORITY); yt1.start();

YieldTest yt2 = new YieldTest("低級");
    yt2.setPriority(MIN_PRIORITY);
    yt2.start();
}

}

<img src="https://img2018.cnblogs.com/blog/1418970/201906/1418970-20190609175309658-2035292882.png" width="370" />
sleep和yield的區別:
*    sleep暫停當前線程後,會給其餘線程執行機會,不會理會其餘線程的優先級;但yield只會給優先級相同或更高的線程執行機會
*    sleep將線程轉入阻塞狀態;yield將線程轉入就緒狀態
*    sleep拋出InterruptedException異常;yield不會
*    sleep比yield有更好的移植性

##    3總結:
*    Java線程對象Thread的狀態包括:New/Runnable/Blocked/Waiting/Timed Waiting/Terminated
*    經過對另外一個線程對象調用join()方法能夠等待其執行結束
*    能夠指定等待時間,超過等待時間線程仍然沒有結束就再也不等待
*    對已經運行結束的線程調用join()方法會馬上返回
*    守護線程是爲其餘線程服務的線程
*    全部非守護線程都執行完畢後,虛擬機退出
*    守護線程不能持有資源(如打開文件等)
相關文章
相關標籤/搜索