jvm源码debug native方法,并手写自定义线程,实现对java侧run方法回调
目录回顾 thread 的start0 方法,我们简化下,其实就是 调用 内核线程 pthread_create ,然后这个方法等待 java_start 方法执行,java_start 方法回调 java端run方法。2.手写模拟过程java端 我们写个类2) 可以看到 start0 就是 native方法 ,完全模拟thread的调用过程3)生成的.h 文件处理4)编写 c++文件5)将上述
·
目录
2) 可以看到 start0 就是 native方法 ,完全模拟thread的调用过程
5)将上述 2个文件 放我们的linux服务器上 ,为了方便我直接放 openjdk 的bin上了
6)生成 .so文件 ,也就是java代码中 load的so文件
1.回顾 thread 的start0 方法,我们简化下,其实就是 调用 内核线程 pthread_create ,然后这个方法等待 java_start 方法执行,java_start 方法回调 java端run方法。
核心点就是 熟悉jni用法,jni就是说 比如 java的一些实现用c++ 方法写的,java端怎么调用呢?通过jni实现。java---》native---->通过jni 找到对应的 动态库,也就是c++实现的方法上。这个也是很多jvm层实现的原理。
2.手写模拟过程
-
java端 我们写个类
package com.yk.jdk;
public class JniTest {
static {
//表明加载的so位置。
System.load("/home/soft/openjdk/openjdk-8-src-b132-03_mar_2014/openjdk/build/linux-x86_64-normal-server-slowdebug/jdk/bin/jniTest.so");
}
public static void main(String[] args) {
JniTest jniTest=new JniTest();
jniTest.start();
}
public void start(){
start0();
}
//run方法
public void run(){
System.out.println("JniTest.run");
}
private native void start0();
}
2) 可以看到 start0 就是 native方法 ,完全模拟thread的调用过程
我们用javah 命名生成对应的 .h 文件,为了后面方便,后面代码放linux上执行 这里生成的时候 需要去掉包名,不然到时候还得把包拷贝过去。
在下图 class 位置处,打开终端:
带上包名
3)生成的.h 文件处理
包名去掉
文件名也对应去掉 包名
4)编写 c++文件
//引入头文件
#include <pthread.h>
#include <stdio.h>
//上一步生成的.h 文件
#include "JniTest.h"
pthread_t pid;//定义变量,接受创建后的线程id
JavaVM *javaVM;
int flag;//0 INITIALIZED 1 RUNNABLE
void* java_start(void* arg){
JNIEnv *env=NULL;
(*javaVM)->AttachCurrentThread(javaVM,&env,NULL);
jclass cls;
jobject obj;
jmethodID cid;
jmethodID rid;
jint ret=0;
//通过虚拟机找到java的类(MyThread)
cls=(*env)->FindClass(env,"JniTest");
if(cls==NULL){
printf("class is not found!\n");
}
//如果找到该类,此时通过无参构造函数new出来
cid=(*env)->GetMethodID(env,cls,"<init>","()V");
if(cid==NULL){
printf("constructor is not found!\n");
}
//通过构造函数实例化
obj=(*env)->NewObject(env,cls,cid);
if(obj==NULL){
printf("NewObject is error!\n");
}
//找到run方法
rid=(*env)->GetMethodID(env,cls,"run","()V");
if(rid==NULL){
printf("RUN method is not found!\n");
}
while(flag==0){
usleep(1000000);
printf("thread state is INITIALIZED!\n");
}
printf("thread state is RUNNABLE!\n");
//开始调用run
(*env)->CallIntMethod(env,obj,rid,NULL);
}
JNIEXPORT void JNICALL Java_JniTest_start0(JNIEnv *env, jobject obj){
pthread_create(&pid, NULL, java_start, NULL);
// while(1){
usleep(5000000);
flag=1;
// printf("this is start0 method!\n");
//}
}
//jvm启动的时候调用,jvm对象返回出去
JNIEXPORT jint JNI_OnLoad(JavaVM* vm,void* reserved){
javaVM=vm;
return JNI_VERSION_1_8;
}
int main()
{
return 0;
}
5)将上述 2个文件 放我们的linux服务器上 ,为了方便我直接放 openjdk 的bin上了
6)生成 .so文件 ,也就是java代码中 load的so文件
gcc -fPIC -I /home/soft/openjdk/openjdk-8-src-b132-03_mar_2014/openjdk/build/linux-x86_64-normal-server-slowdebug/jdk/include/ -I /home/soft/openjdk/openjdk-8-src-b132-03_mar_2014/openjdk/build/linux-x86_64-normal-server-slowdebug/jdk/include/linux/ -shared -o jniTest.so main.c
7)编译java文件并运行 (需要去掉 包名)
./javac JniTest.java
./java JniTest
可以看出我们的jni完整跑好了,并且回调了 java端的 run方法!
欢迎 收藏 点赞!!!原创不易。
更多推荐
已为社区贡献1条内容
所有评论(0)