JNI-Thread中start方法的呼叫與run方法的回撥分析
阿新 • • 發佈:2020-11-06
### **前言**
在java程式設計中,執行緒Thread是我們經常使用的類。那麼建立一個Thread的本質究竟是什麼,本文就此問題作一個探索。
內容主要分為以下幾個部分
1.JNI機制的使用
2.Thread建立執行緒的底層呼叫分析
3.系統執行緒的使用
4.Thread中run方法的回撥分析
5.實現一個jni的回撥
## **1.JNI機制的基本使用**
當我們new出一個Thread的時候,僅僅是建立了一個java層面的執行緒物件,而只有當Thread的start方法被呼叫的時候,一個執行緒才真正開始執行了。所以start方法是我們關注的目標
檢視Thread類的start方法
```java
public synchronized void start() {
if (threadStatus != 0)
throw new IllegalThreadStateException();
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
}
}
}
```
Start方法本身並不複雜,其核心是start0(),真正地將執行緒啟動起來。
接著我們檢視start0()方法
```java
private native void start0();
```
可以看到這是一個native方法,這裡我們需要先解釋一下什麼是native方法。
眾所周知java是一個跨平臺的語言,用java編譯的程式碼可以執行在任何安裝了jvm的系統上。然而各個系統的底層實現肯定是有區別的,為了使java可以跨平臺,於是jvm提供了叫java native interface(JNI)的機制。當java需要使用到一些系統方法時,由jvm幫我們去呼叫系統底層,而java本身只需要告知jvm需要做的事情,即呼叫某個native方法即可。
例如,當我們需要啟動一個執行緒時,無論在哪個平臺上,我們呼叫的都是start0方法,由jvm根據不同的作業系統,去呼叫相應系統底層方法,幫我們真正地啟動一個執行緒。因此這就像是jvm為我們提供了一個可以作業系統底層方法的介面,即JNI,java本地介面。
在深入檢視start0()方法之前,我們先實現一個自己的JNI方法,這樣才能更好地理解start0()方法是如何呼叫到系統層面的native方法。
首先我們先定義一個簡單的java類
```java
package cn.tera.jni;
public class JniTest {
public native void jniHello();
public static void main(String[] args) {
JniTest jni = new JniTest();
jni.jniHello();
}
}
```
在這個類中,我們定義了一個jniHello的native方法,然後在main方法中對其進行呼叫。
接著我們呼叫javac命令將其編譯成一個class檔案,但和平時不同,我們需要加一個-h引數,生成一個頭檔案
```
javac -h . JniTest.java
```
注意-h後面有一個.,意思是生成的標頭檔案,存放在當前目錄
這時我們可以看到在當前目錄下生成了2個新檔案
**JniTest.class**:JniTest類的位元組碼
**cn_tera_jni_JniTest.h**:.h標頭檔案,這個檔案是C和C++中所需要用到的,其中定義了方法的引數、返回型別等,但不包含實現,類似java中的介面,而java程式碼正是通過這個“介面”找到真正需要執行的方法。
我們檢視該.h檔案,其中就包含了jniHello方法的定義,當然需要注意到的是,這裡的方法名和.h檔案本身的命名是jni根據我們類的包名和類名確定出來的,不能修改。
```c
/* DO NOT EDIT THIS FILE - it is machine generated */
#