JNI - 线程和jobject的问题

9

我调用了一个创建另一个线程的本地程序,该程序会附加到JVM。现在我想要访问JVM的方法,但却失败了。以下是代码:

//
// This is the native function that gets called first. 
// it creates another thread which runs, and also calls the printing-methods in my
// java applet. 
//
JNIEXPORT void JNICALL Java_EIGC_1Applet_app_1native_native_1start(JNIEnv* jenv, jobject job) {

    printAppletConsole(jenv,job,"unused atm");
    // save current java VM;
    // save main applet class;
    // used by main thread
    jenv->GetJavaVM(&applet_java_jvm);
    m_job = job;


    // create the working and start it
    applet_thread_main = new EIGC_Applet_thread(&main);
    applet_thread_main->start();
}


//
// This is the running thread that was created
// This will run and call the printing method in the applet
//
unsigned __stdcall main(void* args) {
    // The JNIEnv
    JNIEnv* jenv = new JNIEnv();

    // attach thread to running JVM
    applet_java_jvm->AttachCurrentThread((void**)jenv,NULL);

    // main running loop
    while (true) {
         Sleep(1000);
         printAppletConsole(jenv,m_job,"unused");
    }

    applet_thread_main->stop();
    return 0;
    }


//
// Calls the "writeConsole()" method in applet which prints "test" in a JTextArea
//
void printAppletConsole(JNIEnv* jenv,jobject job,char* text) {
    jclass cls = jenv->GetObjectClass(job);
    jmethodID mid = jenv->GetMethodID(cls,"writeConsole","()V");
    if (mid==NULL) { 
            printf("Method not found");
    }
    else {
        jenv->CallVoidMethod(job,mid);
    }
}

我有一个问题:

1)在新创建的线程中,当我尝试调用printAppletConsole时,JVM会挂起并停留在GetObjectClass()上。为什么会这样?

我的猜测是由于我创建了一个新的线程,所以需要访问jobject的新实例,但我不确定如何做到这一点。

谢谢!

1个回答

7
m_job = job;

这只是保留了本地引用,但是一旦返回 java,它就是无效的。您需要使用 NewGlobalRef 创建全局引用并存储它。

JNIEnv* jenv = new JNIEnv();
applet_java_jvm->AttachCurrentThread((void**)jenv,NULL);

Should be:

JNIEnv* jenv = 0:
applet_java_jvm->AttachCurrentThread(&jenv,NULL);

编辑:对于旧版本的JNI,请使用以下内容:

JNIEnv* jenv = 0:
applet_java_jvm->AttachCurrentThread((void **) &jenv,NULL);

  1. 所以例如在printConsole函数中,new_job = NewGlobalRef(m_job),我需要在函数完成后删除new_job吗?
  2. 你确定关于JNIEnv的初始化吗?如果我像这样做JNIEnv jenv = 0,它会崩溃,并且编译器不喜欢&jenv,因为它不是一个void**指针。谢谢您先生!
- KaiserJohaan
1
不要在Java_EIGC_1Applet_app_1native_native_1start中使用m_job = jenv->NewGlobalRef(job)。当您完全完成后,请调用jenv->DeleteGlobalRef(m_job) - Erik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接