如何获取异步调用的JNI接口指针(JNIEnv*)

Akh*_*esh 69 c java java-native-interface multithreading

我了解到JNI接口指针(JNIEnv*)仅在当前线程中有效.假设我在本机方法中启动了一个新线程; 它如何异步发送事件到Java方法?由于这个新线程不能有(JNIEnv*)的引用.为(JNIEnv*)存储全局变量显然不起作用?

mai*_*n-- 82

您可以使用获取指向JVM(JavaVM*)的指针JNIEnv->GetJavaVM.您可以安全地将该指针存储为全局变量.后来,在新的线程,您可以使用AttachCurrentThread新的线程连接到JVM,如果你创造了它在C/C++或者干脆GetEnv如果您创建在Java代码中的线程,我不因为JNI假定会传给你一个JNIEnv*,然后和你不会有这个问题.

    // JNIEnv* env; (initialized somewhere else)
    JavaVM* jvm;
    env->GetJavaVM(&jvm);
    // now you can store jvm somewhere

    // in the new thread:
    JNIEnv* myNewEnv;
    JavaVMAttachArgs args;
    args.version = JNI_VERSION_1_6; // choose your JNI version
    args.name = NULL; // you might want to give the java thread a name
    args.group = NULL; // you might want to assign the java thread to a ThreadGroup
    jvm->AttachCurrentThread((void**)&myNewEnv, &args);
    // And now you can use myNewEnv
Run Code Online (Sandbox Code Playgroud)

  • 请注意,如果您不需要任何特殊设置,则"AttachCurrentThread"的第二个参数可以为NULL,并且如果您没有附加到开头,则应该确保在完成时调用"DetachCurrentThread"(否则您将' ll积累无用的'Thread`对象,这些对象永远不会被GC'd). (15认同)
  • @DenisKniazhev正确.C没有类,因此您无法在指针上调用方法.在C++中,JNI提供了自动传递env指针的包装类,但在C中你必须手动传递它. (2认同)

Ada*_*dam 71

在使用JNI从Java到C++的同步调用中,JVM已经设置了"环境",但是从任意C++线程转向另一个方向它可能不是

因此,您需要按照以下步骤操作

  • 使用获取JVM环境上下文 GetEnv
  • 如有必要,使用附加上下文 AttachCurrentThread
  • 使用正常调用方法 CallVoidMethod
  • 分开使用 DetachCurrentThread

完整的例子.请注意我在过去的博客中已经详细介绍了这一点

void callback(int val) {
    JNIEnv * g_env;
    // double check it's all ok
    int getEnvStat = g_vm->GetEnv((void **)&g_env, JNI_VERSION_1_6);
    if (getEnvStat == JNI_EDETACHED) {
        std::cout << "GetEnv: not attached" << std::endl;
        if (g_vm->AttachCurrentThread((void **) &g_env, NULL) != 0) {
            std::cout << "Failed to attach" << std::endl;
        }
    } else if (getEnvStat == JNI_OK) {
        //
    } else if (getEnvStat == JNI_EVERSION) {
        std::cout << "GetEnv: version not supported" << std::endl;
    }

    g_env->CallVoidMethod(g_obj, g_mid, val);

    if (g_env->ExceptionCheck()) {
        g_env->ExceptionDescribe();
    }

    g_vm->DetachCurrentThread();
}
Run Code Online (Sandbox Code Playgroud)

  • 与这个问题相关的答案中唯一的部分是`GetEnv`,`AttachCurrentThread`和`DetachCurrentThread`,甚至没有解释. (13认同)