目录
回顾 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端 我们写个类
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方法!
欢迎 收藏 点赞!!!原创不易。



