Java JNI 使用与要点
当我们需要在Java程序中调用某个C++函数时,就需要通过JNI调用编译好的so文件,并在java代码中加载和使用对应so文件中的函数。由于jvm支持不同环境,而cpp与编译内核有关,所以还需要考虑环境因素。在多线程中调用so文件还需要考虑到线程安全。
JNI使用方法
Java中注册需要使用的方法
主要是将需要使用JNI load的方法注册为native。
package com.test.jni
public class JNITest {
long myId = 0;
public native long getId(long yourId);
}
cpp中编写和编译相应的方法
JNIEXPORT long JNICALL Java_com_test_jni_JNITest_getId(JNIEnv *env, jclass j_class, jlong yourId) {
env->GetJavaVM(&gs_jvm);
long process_id = 0;
// process function to processId
// ...
return process_id;
}
编译成libjnitest.so文件后放置在项目的resources文件夹下可以通过直接路径/加载。
在Java的class中加载so文件
InputStream in = JNITest.class.getResourceAsStream("/libjnitest.so");
File soFile = File.createTempFile("libjnitest", ".so");
Files.copy(in, soFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
in.close();
System.load(soFile.toString);
以上代码段从so文件中加载native方法,每个JVM只会load一次,因此建议放在static代码块中执行。
使用注意事项
执行环境
Java程序的执行环境只与JVM有关,但是so文件的执行则与机器有关。需要执行Java程序的机器与编译so文件的机器的c++编译版本等相同。
多线程
如果Java代码中有多线程调用同一个对象的native方法(尤其是在分布式计算框架,如Spark,中调用JNI的方法),会报错:
*** Error in 'java': double free or corruption (out): 0x00007f665c04a830 ***
出现这种问题的原因就是多线程同时访问native方法造成的。解决方法有两种:
- native方法用synchronized关键字修饰。
- 在cpp中实现线程安全的访问,可以参考后续的参考文献解决。
本文参考:https://blog.csdn.net/lovingprince/article/details/2793504 本文参考:https://stackoverflow.com/questions/22491797/java-double-free-or-corruption