多线程JNI 获取全局 jvm
  HvTJUzsxOBtS 2023年11月22日 18 0


一、前言
在JNI开发时,最重要的就是JNIEnv *env这个参数,它代表着Java本地接口环境(Java Native Interface Environment),通过它可以在native层中与java层进行交互。因此在每个定义的native方法中都有这个参数。

二、问题描述
在项目中遇到的一个问题就是在native层中的回调函数里调用java层的方法,实时向java层传输算法结果,这里就需要在回调函数中定义JNIEnv *env这个参数。我当时认为只要定义一个全局变量env,在其他方法中进行赋值,然后就能在回调函数中使用了,其实是错的!当然我也这么试了,最终结果是程序直接挂掉!

事实上,JNIEnv是一个与线程相关的变量,不同线程的JNIEnv彼此独立。JavaVM是虚拟机在JNI层的代表,在一个虚拟机进程中只有一个JavaVM,因此该进程的所有线程都可以使用这个JavaVM。当后台线程需要调用JNIEnv时,在native层中使用全局变量保存JavaVM尤为重要,这样使得后台线程能通过JavaVM获得JNIEnv。

三、问题解决
1、定义一个全局变量JavaVM:
JavaVM* g_jvm = NULL;
//在某个含有env环境的方法中获取JavaVM
env->GetJavaVM(&_jvm);
或者可以在JNI_OnLoad中进行赋值,因为它是最开始执行的函数
 

jint JNI_OnLoad(JavaVM* vm, void* reserved)
{  
    g_jvm=vm;
    return JNI_VERSION_1_6;
}

2、在回调函数中利用全局JavaVM生成该线程下的env:

int status;
JNIEnv* _jniEnv = NULL;
status = g_jvm->GetEnv((void **)&_jniEnv, JNI_VERSION_1_6);
JavaVMAttachArgs args = { JNI_VERSION_1_6, __FUNCTION__, __null };
if(status < 0)
{
    status = g_jvm->AttachCurrentThread(&_jniEnv, &args);//获得了可以使用的env
    if(status < 0)
    {
        _jniEnv = NULL;
    }
}

但是在之后的开发中又遇到了其他问题, _jniEnv->FindClass(…)返回值一直是null,索性我就直接定义一个全局的jclass jglobalClass,在其他有env环境中获取全局的 jglobalClass:

jclass jcls=env->FindClass(…);
jglobalClass=reinterpret_cast<jclass>(env->NewGlobalRef(jcls));//需要强制转换

在最后别忘了还要调用DeleteGlobalRef来释放全局引用!!!


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月22日 0

暂无评论

推荐阅读
HvTJUzsxOBtS