HotSpot中的線程模型是Java線程(java.lang.Thread)與本地操作系統(tǒng)線程一一映射,本地線程在Java線程啟動(dòng)(調(diào)用start())時(shí)創(chuàng)建, 并在終止時(shí)回收。操作系統(tǒng)負(fù)責(zé)調(diào)度本地線程給可用的CPU來執(zhí)行趋艘。Java線程優(yōu)先級(jí)和操作系統(tǒng)優(yōu)先級(jí)之間的關(guān)系是相當(dāng)復(fù)雜的衡奥,并且因操作系統(tǒng)而異。
JVM線程類結(jié)構(gòu)
JVM中線程模型是相當(dāng)重要的一部分么抗,如執(zhí)行虛擬機(jī)指令的VM線程、執(zhí)行內(nèi)存垃圾回收的GC線程亚铁、采集虛擬機(jī)內(nèi)存及CPU狀況的監(jiān)控線程蝇刀, 還有專門用于執(zhí)行用戶線程的Java線程,如此多的線程之間是怎樣一種聯(lián)系和區(qū)別徘溢,我們一起來看一下吞琐。
JVM內(nèi)部主要的線程主要分為以下幾類:
// ==================================================
// 線程實(shí)現(xiàn)類結(jié)構(gòu)
// ==================================================
// Class hierarchy
// - Thread
// - NamedThread 支持命名的非Java線程
// - VMThread VM原始線程,用于執(zhí)行VM操作
// - ConcurrentGCThread 并發(fā)GC線程
// - WorkerThread 工作線程
// - GangWorker 一組線程然爆,類似線程池
// - GCTaskThread GC任務(wù)線程
// - JavaThread C++層面的Java線程實(shí)現(xiàn)
// - various subclasses eg CompilerThread, ServiceThread
// 各種子類站粟,如:編譯器線程,服務(wù)線程
// - WatcherThread 監(jiān)視器線程曾雕,用于模擬計(jì)時(shí)器中斷
比較重要的還有OSThread操作系統(tǒng)層面的本地線程并且包含跟蹤線程狀態(tài)所需的附加操作系統(tǒng)級(jí)信息奴烙。OSThread還包含一個(gè)特定于平臺(tái)的“句柄”,用于標(biāo)識(shí)操作系統(tǒng)的實(shí)際線程
線程的創(chuàng)建與銷毀
在JVM內(nèi)部產(chǎn)生一個(gè)線程的基本方法有兩種 - 調(diào)用java.lang.Thread的start()方法 - 通過JNI attach到一個(gè)已經(jīng)存在的本地線程上
在java.lang.Thread啟動(dòng)時(shí),JVM會(huì)分別創(chuàng)建一個(gè)相關(guān)聯(lián)的JavaThread和OSThread對(duì)象切诀,最終創(chuàng)建本地線程揩环。 在準(zhǔn)備完所有的VM狀態(tài)(例如線程本地存儲(chǔ)和分配緩沖區(qū),同步對(duì)象等等)之后幅虑,本地線程啟動(dòng)丰滑。 本地線程完成初始化, 然后執(zhí)行啟動(dòng)方法倒庵,該方法導(dǎo)致執(zhí)行java.lang.Thread對(duì)象的run()方法褒墨,然后在返回時(shí)在處理任何未捕獲的異常之后 終止該線程,并且交互 與VM一起檢查此線程的終止是否需要終止整個(gè)VM擎宝。 線程終止釋放所有分配的資源貌亭,從一組已知線程中 刪除JavaThread,調(diào)用OSThread和JavaThread的析構(gòu)函數(shù)认臊,并最終在初始啟動(dòng)方法完成時(shí)停止執(zhí)行圃庭。
C++層面的JavaThread狀態(tài)
源碼位于src/hotspot/share/utilities/globalDefinitions.hpp
enum JavaThreadState {
_thread_uninitialized = 0, // should never happen (missing initialization)
_thread_new = 2, // just starting up, i.e., in process of being initialized
_thread_new_trans = 3, // corresponding transition state (not used, included for completness)
_thread_in_native = 4, // running in native code
_thread_in_native_trans = 5, // corresponding transition state
_thread_in_vm = 6, // running in VM
_thread_in_vm_trans = 7, // corresponding transition state
_thread_in_Java = 8, // running in Java or in stub code
_thread_in_Java_trans = 9, // corresponding transition state (not used, included for completness)
_thread_blocked = 10, // blocked in vm
_thread_blocked_trans = 11, // corresponding transition state
_thread_max_state = 12 // maximum thread state+1 - used for statistics allocation
};
最主要的有四個(gè): - _thread_new : 剛啟動(dòng)但還沒有初始化 - _thread_in_native : 在執(zhí)行本地代碼 - _thread_in_vm : 在執(zhí)行JVM本身的代碼 - _thread_in_Java : 在執(zhí)行解釋的或編譯的Java代碼
Java語言層面的線程狀態(tài)
源碼位于src/hotspot/share/classfile/javaClasses.hpp
這些線程狀態(tài)主要用于JVMTI和MANGEMENT狀態(tài)輸出。
enum ThreadStatus {
NEW = 0,
RUNNABLE = JVMTI_THREAD_STATE_ALIVE + // runnable / running
JVMTI_THREAD_STATE_RUNNABLE,
SLEEPING = JVMTI_THREAD_STATE_ALIVE + // Thread.sleep()
JVMTI_THREAD_STATE_WAITING +
JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT +
JVMTI_THREAD_STATE_SLEEPING,
IN_OBJECT_WAIT = JVMTI_THREAD_STATE_ALIVE + // Object.wait()
JVMTI_THREAD_STATE_WAITING +
JVMTI_THREAD_STATE_WAITING_INDEFINITELY +
JVMTI_THREAD_STATE_IN_OBJECT_WAIT,
IN_OBJECT_WAIT_TIMED = JVMTI_THREAD_STATE_ALIVE + // Object.wait(long)
JVMTI_THREAD_STATE_WAITING +
JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT +
JVMTI_THREAD_STATE_IN_OBJECT_WAIT,
PARKED = JVMTI_THREAD_STATE_ALIVE + // LockSupport.park()
JVMTI_THREAD_STATE_WAITING +
JVMTI_THREAD_STATE_WAITING_INDEFINITELY +
JVMTI_THREAD_STATE_PARKED,
PARKED_TIMED = JVMTI_THREAD_STATE_ALIVE + // LockSupport.park(long)
JVMTI_THREAD_STATE_WAITING +
JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT +
JVMTI_THREAD_STATE_PARKED,
BLOCKED_ON_MONITOR_ENTER = JVMTI_THREAD_STATE_ALIVE + // (re-)entering a synchronization block
JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER,
TERMINATED = JVMTI_THREAD_STATE_TERMINATED
};
SLEEPING 調(diào)用Thread.sleep()進(jìn)入
IN_OBJECT_WAIT 調(diào)用Object.wait()進(jìn)入
IN_OBJECT_WAIT_TIMED 調(diào)用Object.wait(long)進(jìn)入
PARKED 調(diào)用LockSupport.park()進(jìn)入
PARKED_TIMED 調(diào)用LockSupport.park(long)進(jìn)入
Java線程狀態(tài)名稱
const char* java_lang_Thread::thread_status_name(oop java_thread) {
assert(_thread_status_offset != 0, "Must have thread status");
ThreadStatus status = (java_lang_Thread::ThreadStatus)java_thread->int_field(_thread_status_offset);
switch (status) {
case NEW : return "NEW";
case RUNNABLE : return "RUNNABLE";
case SLEEPING : return "TIMED_WAITING (sleeping)";
case IN_OBJECT_WAIT : return "WAITING (on object monitor)";
case IN_OBJECT_WAIT_TIMED : return "TIMED_WAITING (on object monitor)";
case PARKED : return "WAITING (parking)";
case PARKED_TIMED : return "TIMED_WAITING (parking)";
case BLOCKED_ON_MONITOR_ENTER : return "BLOCKED (on object monitor)";
case TERMINATED : return "TERMINATED";
default : return "UNKNOWN";
};
}
實(shí)例驗(yàn)證
隨便實(shí)現(xiàn)一個(gè)Java線程并在內(nèi)部sleep失晴,
public class Main {
public static void main(String[] args) throws IOException {
Thread t = new DemoThread();
// 啟動(dòng)線程
t.start();
System.in.read();
}
static class DemoThread extends Thread {
@Override
public void run() {
try {
TimeUnit.HOURS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
然后通過jstack命令獲取其運(yùn)行狀態(tài):
$ jps
82005 Jps
81869 Main
81868 Launcher
$ jstack 81869
2018-07-02 00:28:52
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.151-b12 mixed mode):
"Attach Listener" #12 daemon prio=9 os_prio=31 tid=0x00007f99af000000 nid=0x1307 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Thread-0" #11 prio=5 os_prio=31 tid=0x00007f99ae817000 nid=0x5a03 waiting on condition [0x0000700011471000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:340)
at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
at com.workholiday.demoapp.Main$DemoThread.run(Main.java:30)
"Service Thread" #10 daemon prio=9 os_prio=31 tid=0x00007f99ae800800 nid=0x5603 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
...
"Finalizer" #3 daemon prio=8 os_prio=31 tid=0x00007f99ab814000 nid=0x3903 in Object.wait() [0x0000700010ad3000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x000000076ab08ec8> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
- locked <0x000000076ab08ec8> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)
"main" #1 prio=5 os_prio=31 tid=0x00007f99ae802000 nid=0x1c03 runnable [0x000070000ffb2000]
java.lang.Thread.State: RUNNABLE
at java.io.FileInputStream.readBytes(Native Method)
at java.io.FileInputStream.read(FileInputStream.java:255)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
at java.io.BufferedInputStream.read(BufferedInputStream.java:265)
- locked <0x000000076ab20660> (a java.io.BufferedInputStream)
at com.workholiday.demoapp.Main.main(Main.java:19)
通過日志輸出會(huì)發(fā)現(xiàn)線程中的狀態(tài) - RUNNABLE - TIMED_WAITING (sleeping) - WAITING (on object monitor)
正是通過java_lang_Thread::thread_status_name()方法獲取的剧腻。