上篇文章:java多線程解說【貳】_java記憶體模型
在上文中我們分析了java記憶體模型和volatile、synchronized的實作原理。在這篇文章中,我們繼續分析一下Thread的常用api有哪些,以及它們是如何實作的。
Thread的結構
我們先通過源碼看看Thread中主要封裝了哪些對象:
private char name[]; //線程的名稱
private int priority; //線程的優先級
private boolean daemon = false; //該線程是否為守護線程,預設為false
private Runnable target; //該線程要執行的任務
private ThreadGroup group; //該線程歸屬的線程組
private ClassLoader contextClassLoader; //加載器,預設為AppClassLoader
private static int threadInitNumber; //數字辨別匿名線程
ThreadLocal.ThreadLocalMap threadLocals = null; //線程私有變量
private long stackSize; //配置設定給線程的棧空間大小,預設0(不限制)
private long tid; //線程id
private static long threadSeqNumber; //線程式列
private volatile int threadStatus = 0; //線程運作狀态,預設是0(NEW)
volatile Object parkBlocker; //java.util.concurrent.locks.LockSupport.park使用
private volatile Interruptible blocker; //枚舉字段,interrupt方法使用
private final Object blockerLock = new Object(); //更改blocker值時使用,作為鎖的對象
Thread的構造方法
其完整的構造方法聲明如下:
public Thread(ThreadGroup group, Runnable target, String name, long stackSize);
其中,ThreadGroup如果不指定,則為目前線程(即啟動該線程的線程)的ThreadGroup;Runnable就是該線程将要執行的類,分兩種情況,一種是繼承了Thread類,一種是實作了Runnable接口;name就是線程的名稱,如果不指定則為"Thread-索引号(索引從0開始)";stackSize是JVM配置設定給線程的棧空間大小,預設0(不限制)。
Thread關于自身資訊的API
setName(String name)/getName()
讀寫線程名稱
getThreadGroup()
讀線程組
activeCount()
擷取目前線程所線上程組上的存活線程
setDaemon(boolean on)
設定目前線程為守護線程。守護線程不應執行重要的任務,一般用于記錄日志或監控之用,因為jvm當隻有守護線程在運作時就停止
isDaemon()
判斷該線程是否是守護線程
checkAccess()
判斷目前線程是否有權限去操作該線程
holdsLock(Object obj)
判斷該線程是否持有某對象的鎖
getId()
擷取目前jvm中該線程的唯一标示
isAlive()
判斷該線程是否存活,标準是線程已啟動但還沒有執行完畢
getState()
擷取該線程狀态,傳回值為枚舉,包括NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING和TERMINATED
Thread關于執行的API
start()
正确的啟動一個線程的方法。先完成一些初始化動作,然後會通知JVM調用線程的run()方法
run()
隻是單純地執行線程代碼,并沒有啟動一個新的線程。
join(long millis, int nanos)
保證指定時間以内,在JVM中隻有該線程在運作。millis是等待的毫秒數,nanos是微秒數(參數可省)。如果millis填0,則一直等到目前線程執行完畢,JVM才會排程其他線程執行。
exit()
讓該線程運作結束之前做下自身資源清理工作
yield()
當該線程讓出CPU,給其他線程一個擷取排程的機會,但是不確定一定會排程到其他線程上。
sleep(long millis, int nanos)
讓該線程在指定時間以内休眠,需要注意的是在休眠過程中該線程不會釋放持有的鎖。millis是等待的毫秒數,nanos是微秒數(參數可省)。
interrupt()
它不會中斷一個正在運作的線程,實際上是線上程受到阻塞時抛出一個中斷信号,這樣線程就得以退出阻塞的狀态。更确切的說,如果線程被wait、join或sleep阻塞時,那麼它将接收到一個中斷異常(InterruptedException),我們可以在異常塊裡調用本方法,進而提早地終結被阻塞狀态。如果線程沒有被阻塞,這時調用interrupt()将不起作用,僅僅是設定中斷标志位為true的情況
interrupted()
判斷該線程中斷辨別是否為true,傳回該辨別并将辨別置為false
isInterrupted()
判斷該線程中斷辨別是否為true,傳回該辨別。其實該方法和interrupted()方法底層調用的都是isInterrupted(boolean isClearState),隻不過參數不同而已
Thread API中不鼓勵使用的方法
setPriority(int newPriority)/getPriority()
讀寫線程的優先級。關于優先級有三個枚舉值:
MIN_PRIORITY = 1;
NORM_PRIORITY = 5;
MAX_PRIORITY = 10;
資料越大,優先級越高。但是這個方法不推薦使用,是因為并不是所有的JVM都會嚴格按照該優先級的設定而排程線程,而且在有的JVM中,當一個線程的優先級設定過高會導緻隻運作該線程,在該線程運作完之前不會排程到其他線程上
suspend()/resume()
暫停/喚醒該線程。也不推薦使用,因為暫停并不釋放鎖,可能導緻死鎖;而且暫停的線程狀态仍然是RUNNABLE,排查問題很難
destroy()
銷毀該線程,但沒有進行清理工作。線程持有的鎖(monitor)不會釋放
stop(Throwable obj)
停止線程,但沒有進行清理工作。線程持有的鎖(monitor)不會釋放
下篇文章:java多線程解說【肆】_鎖實作:wait()/notify()