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个文件 放我们的linux服务器上 ,为了方便我直接放 openjdk 的bin上了

6)生成 .so文件 ,也就是java代码中 load的so文件

7)编译java文件并运行 (需要去掉 包名)


1.回顾 thread 的start0 方法,我们简化下,其实就是 调用 内核线程 pthread_create ,然后这个方法等待 java_start 方法执行,java_start 方法回调 java端run方法。

核心点就是 熟悉jni用法,jni就是说 比如 java的一些实现用c++ 方法写的,java端怎么调用呢?通过jni实现。java---》native---->通过jni 找到对应的 动态库,也就是c++实现的方法上。这个也是很多jvm层实现的原理。

2.手写模拟过程

  1. 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上了

449b52955879577e0d0b5fd18e912d46.png

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


fa8cb66b67f2179d9d88e5761a2a9629.png

可以看出我们的jni完整跑好了,并且回调了 java端的 run方法!

欢迎 收藏 点赞!!!原创不易。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猫猫大神

有帮助的话,请打赏官人一下哦!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值