linux下使用jni实现c++调用java程序(3)多线程jni使用

来源:互联网 发布:windows安装无法继续 编辑:程序博客网 时间:2024/05/17 05:18
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)对于每个线程,首先:
glb_jvm->AttachCurrentThread((void **) &env, NULL);//attach 当前线程到jvm中
env->MonitorEnter(glb_obj);//进入监控的java对象glb_obj,没一个java对象都有一个相关联的监视器
             env->PushLocalFrame(100);              //创建一个新的本地参考帧
(4)之后就可以FindClass、GetMethodID、NewObject、CallObjectMethod调用java类中的函数了,最后记得:
            DetachCurrentThread();
(5)只有最后main函数退出之前,才没有线程在等待,这是才可以有效地DestroyJavaVM();