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

时间:2012-10-15 17:15:57

标签: java c multithreading java-native-interface

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

2 个答案:

答案 0 :(得分:78)

您可以使用JNIEnv->GetJavaVM获取指向JVM(JavaVM*)的指针。您可以安全地将该指针存储为全局变量。稍后,在新线程中,您可以使用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

答案 1 :(得分:69)

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

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

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

完整的例子。请注意,我在blog

上已经详细介绍了这一点
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();
}