上次我們了解了多線程的五種創建方法,今天來學習Thread的基本用法。
目錄
run和start
Thread常見的構造方法
Thread的幾個常見屬性
后臺線程
是否存活
線程終止
1.使用標志位
2.使用Thread自帶的標志
等待線程
run和start
首先需要理解Thread的run和start的區別:
run描述了線程要做的工作,start讓內核創建一個PCB,也就是讓操作系統新建一個線程。
如果不調用start,那么就不會在內核中有新的線程。
Thread常見的構造方法
第二、三、四個方法,其實都只是給線程起了個名字,線程默認的名字,叫做thread-0之類的,我們新建一個線程來看一下。
public class demo6 {public static void main(String[] args) {Thread t = new Thread(new Runnable() {@Overridepublic void run() {while(true){System.out.println("hello");}}},"mythread_demo");t.start();}
}
?通過jconsole可以看到我們自己命名的線程出現了。
Thread的幾個常見屬性
?
1.ID 是線程的唯一標識,不同線程不會重復
2.名稱是各種調試工具用到,這里是構造方法里取的名字
3.線程狀態?
4.優先級高的線程理論上來說更容易被調度到
5.關于后臺線程,需要記住一點:JVM會在一個進程的所有非后臺線程結束后,才會結束運行。
6.是否存活,即簡單的理解,為run方法是否運行結束了
7.線程的中斷問題,我們待會再說。
后臺線程
后臺進程,又叫做守護線程。
前臺線程,會阻止進程結束.前臺線程的工作沒做完,進程是完不了的。
后臺線程,不會阻止進程結束.后臺線程工作沒做完,進程也是可以結束的。JVM必須在所有前臺進程結束后,才會結束運行。
代碼里手動創建的線程,默認都是前臺的.包括main 默認也是前臺的.
其他的jvm自帶的線程都是后臺的.
也可以手動的使用setDaemon設置成后臺線程.是后臺線程,就是守護線程。
t.setDaemon(true);
可以用這個代碼把t設置成后臺進程,這樣進程的結束就和t無關。
是否存活
isAlive是在判斷,當前系統里面的這個線程是不是真的有了。
在真正調用start之前,調用t.isAlive就是false。調用start之后,?isAlive就是true。
線程終止
終止的意思是,不是讓線程立即就停止,而是通知線程,你應該要停止了。是否真的停止取決于線程這里具體的代碼寫法。
1.使用標志位
在創建多線程的代碼前面,加上一個flag變量,作為標志位,最后由flag控制進程是否停止。這樣在最后停止時,就是由flag決定的。
但是如果在while(flag)中sleep休眠時,自變量這種方式不能及時響應
但是 sleep 在喚醒的時候,還會做一件事,把剛才設置的這個標志位再設置回 false(清空了標志位)
這就導致,當 sleep 的異常被 catch 完了之后, 循環還要繼續執行!!!
那么就是說,此時的flag并沒有起作用。
因此,這里只是告訴讓這個線程結束.這個線程是否要結束,啥時候結束都是線程內部自己代碼來決定的。
2.使用Thread自帶的標志
while(!Thread.currentThread().isInterrupted()){
t.interrupte就是終止t線程,main 線程調用t.interrupt()相當于main通知 t 你要終止了。
其實跟前面的flag差不過,只是把一個boolean操作封裝到Thread的方法里面了。
interrupt會做兩件事:
1.把線程內部的標志位(boolean)給設置成true。
2.如果線程在進行sleep,就會觸發異常,把sleep喚醒。
但是sleep在喚醒的時候,還會做一件事,把剛才設置的這個標志位再設置回false.(清空了標志位)
這就導致,當sleep的異常被catch完了之后,循環還要繼續執行。
那豈不是加不加這個interru都沒用?反正遇到線程sleep的時候總是會繼續運行?
此時我們可以在循環最后加一個break
?這樣子線程t就會立刻響應你的終止請求。
等待線程
線程是一個隨機調度的過程,等待線程,做的事情,就是在控制兩個線程的結束順序。
通過join來實現
?
?
?
?
?
?