jni调用c++代码时,若c++实现里面采用了多线程,则会出现jvm crash的情况。
查了一下jni的说明,其中提到:
JNIEnv *env指针和
jobject对象都不能跨线程使用,但是java虚拟机jvm可以共享
对于jobject,解决办法是
a、glb_obj = glb_env->NewGlobalRef(obj); //创建一个全局变量
b、jobject obj = glb_env->AllocObject(glb_cls); //在每个线程中都生成一个对象
对于JNIEnv,解决办法是在每个线程中都重新生成一个env
a、JNIEnv *env;
b、glb_jvm->AttachCurrentThread((void **)&env, NULL);
必须是原本就是Java线程(Java代码通过JNI调用native代码时,发起调用的那个肯定是Java线程),或者是让已有的native线程通过JNI来attach到Java环境。
你的每个“C++线程”里都应该要调用AttachCurrentThread()来确保它确实attach到Java环境里了。
so,
jni应用于多线程程序时,我的处理办法是:
(1)主程序运行时,创建jvm和初始化jni,之后的每个线程就只调用GetJavaVM和CallObjectMethod就行了:
glb_env=queryer->createJVM();int tmp=glb_env->GetJavaVM(&glb_jvm);queryer->initJNI(glb_env);queryer->queryExecute(glb_env);
(2)设置全局变量,达到共享jvm的效果:
JavaVM* glb_jvm;jobject glb_obj;JNIEnv* glb_env;jclass glb_cls;JenaQuery* queryer = new JenaQuery;
(3)对于每个线程,首先:
env->PushLocalFrame(100); //创建一个新的本地参考帧glb_jvm->AttachCurrentThread((void **) &env, NULL);//attach 当前线程到jvm中env->MonitorEnter(glb_obj);//进入监控的java对象glb_obj,没一个java对象都有一个相关联的监视器
(4)
之后就可以FindClass、GetMethodID、NewObject、CallObjectMethod调用java类中的函数了,最后记得:
DetachCurrentThread();
(5)只有最后main函数退出之前,才没有线程在等待,这是才可以有效地DestroyJavaVM();