仿写一个Java Thread 底层实现

Java里的线程和操作系统的线程是一一对应的,为了方便理解Thread 类的底层实现,我们可以自己来仿造一个MyThread, 同样接受一个Runable接口,调用start实现run方法。

这是要实现的类

1
2
3
4
5
6
7
public class MyThread {
Runnable mRunnable;
public MyThread(Runnable runnable) {
mRunnable = runnable;
}
native public void start();
}

那么我们先去实现native方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#define TAG    "native-lib" // 这个是自定义的LOG的标识
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG,__VA_ARGS__) // 定义LOGD类型

JavaVM *jvm = 0;
jclass RunnableClass = NULL;
extern "C"
JNIEXPORT void JNICALL
Java_com_test_MyThread_start(JNIEnv *env, jobject thiz) {
LOGD("java invoke start()---------------start");
jclass MyThreadClass = env->FindClass("com/test/MyThread");
RunnableClass = (jclass) env->NewGlobalRef(env->FindClass("java/lang/Runnable"));
jfieldID runnableID = env->GetFieldID(MyThreadClass, "mRunnable", "Ljava/lang/Runnable;");
jobject mRunnable = env->NewGlobalRef(env->GetObjectField(thiz, runnableID));

pthread_t tid;
int ret_t = -1;
ret_t = pthread_create(&tid, NULL, new_thread, mRunnable);
pthread_detach(tid);
if (ret_t != 0) {
printf("pthread_create error \n");
return;
}
LOGD("java invoke start()---------------end");
return;
}

java 调用了start方法进入 c 层面,接下来 主要是通过pthread创建新线程,在新线程里面反调java里面的run方法。

新建的线程 void *new_thread(void *arg)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void *new_thread(void *arg) {
LOGD("new_thread-----------------");
JNIEnv *env;
jobject mRunnable = static_cast<jobject>(arg);
LOGD("new_thread-----------------AttachCurrentThread()");
//将当前线程注册到虚拟机中
jvm->AttachCurrentThread(&env, NULL);
jmethodID run = NULL;
LOGD("new_thread-----------------GetMethodID");
// 拿到run方法
run = env->GetMethodID(RunnableClass, "run", "()V");
LOGD("new_thread-----------------CallVoidMethod");
env->CallVoidMethod(mRunnable, run);
env->DeleteGlobalRef(mRunnable);
LOGD("new_thread-----------------end");
//返回值一定要
return nullptr;
}

加载库的时候做一下初始化

1
2
3
4
5
6
7
8
9
10
11
/*加载库的时候,初始化JavaVM对象,全局复用*/
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env;
if (JNI_OK != vm->GetEnv((void **) &env, JNI_VERSION_1_6)) {
printf("JNI_OnLoad error \n");
return -1;
}
jvm = vm;
LOGD("JNI_OnLoad-----------------------------------");
return JNI_VERSION_1_6;
}

最后在java 里面加载so文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MyThread {
Runnable mRunnable;

static {
System.loadLibrary("native-lib");
System.out.println("load native-lib");
}

public MyThread(Runnable runnable) {
mRunnable = runnable;
}

native public void start();
}

测试

1
2
3
4
5
6
new MyThread(new Runnable() {
@Override
public void run() {
System.out.println("Hello World!");
}
}).start();

结果

1
2
3
4
5
6
7
8
9
10
D/native-lib: JNI_OnLoad-----------------------------------
I/System.out: load native-lib
D/native-lib: java invoke start()---------------start
java invoke start()---------------end
D/native-lib: new_thread-----------------
new_thread-----------------AttachCurrentThread()
new_thread-----------------GetMethodID
new_thread-----------------CallVoidMethod
I/System.out: Hello World!
D/native-lib: new_thread-----------------end