How to obtain JNI interface pointer (JNIEnv *) for asynchronous calls

Akhilesh picture Akhilesh · Oct 15, 2012 · Viewed 62.1k times · Source

I have learned that the JNI interface pointer (JNIEnv *) is only valid in the current thread. Suppose I started a new thread inside a native method; how it can asynchronously send events to a Java method? As this new thread can't have a reference of (JNIEnv *). Storing a global variable for (JNIEnv *) apparently will not work?

Answer

main-- picture main-- · Oct 15, 2012

You can obtain a pointer to the JVM (JavaVM*) with JNIEnv->GetJavaVM. You can safely store that pointer as a global variable. Later, in the new thread, you can either use AttachCurrentThread to attach the new thread to the JVM if you created it in C/C++ or simply GetEnv if you created the thread in java code which I do not assume since JNI would pass you a JNIEnv* then and you wouldn't have this problem.

    // 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