栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

jvm源码debug native方法,并手写自定义线程,实现对java侧run方法回调

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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.手写模拟过程

    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 
#include 
//上一步生成的.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,"","()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方法!

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

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/763437.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号