Search code examples
javac++multithreadingservletsjava-native-interface

JNI, Mulithreading and calling methods


I'm trying to do the following (not sure if I'm missing something or if this is not possible):

I have a Java class (in this particular case a Servlet) that calls a native method.

In this native method I'm spawning a new thread, and in that thread I would like to call a method on that Java object. Is that even possible?

What I tried in the native method that is called (original thread) is to remember the JavaVM instance, so that I can later can attach the other thread to it (seems to work), and make a NewGlobal ref for the jobject:

    JavaVM *vm;
env->GetJavaVM(&vm);

env->NewGlobalRef(jobj)

What I don't know is how to retrieve the jobject in the other thread. If I just pass it the VM crashes, I assume because of an illegal thread access. If I create a new object for the class, I wouldn't have the exact object that I need.

Any ideas?

Thank you, Mark

SOME ADDITIONAL CODE (method names etc. obscured):

The method that is called from the servlet:

JNIEXPORT jstring JNICALL ABC (JNIEnv *env, jobject jobj, some more arguments
{
  JavaVM *vm;
  env->GetJavaVM(&vm);
  env->NewGlobalRef(jobj);

  // spawning new thread (I'm using boost libraries)
  boost::thread t = boost::thread(boost::bind(&XYZ::DEF, instance of XYZ, vm, &jobj);
  ...
}

void XYZ::DEF(JavaVM* vm, jobject* jobj)
{
    JNIEnv* env;
    vm->GetEnv( (void**)&env, JNI_VERSION_1_2);
    vm->AttachCurrentThread((void**)&env, NULL);
    ... then eventually calling another method, but still the same thread, where I'm doing this:

jobject bb = env->NewDirectByteBuffer(...,...); // this crashed when I just used the env from the original thread, seems to work since I'm attaching the second thread to the VM.

// it crashes somewhere during the following code:
jclass cls = env->GetObjectClass(jobj);
jmethodID mid = env->GetMethodID(cls, "callback", "(I)V");
env->CallVoidMethod(jobj, mid, 13);

The crash produces something like this "A fatal error has been detected by the JRE... Problematic frame: V [libjvm.so+0x3e9220]...


Solution

  • You seem to be ignoring the result of NewGlobalRef. You have to use its result in the other thread instead of the original jobj.