在多线程应用程序中使用JNI的正确方法

时间:2012-06-12 08:32:49

标签: java android c++ c multithreading

描述

在我的C ++应用程序类JNIXMLDocument中进行了一些JAVA方法调用。在JNIXMLDocument类的构造函数中,我附加当前线程并将其设置为我的类成员JNIEnv* m_JavaEnv,然后在所有方法中使用它。同样在构造函数中,我试图找到我的JAVA类com/fido/android/framework/service/XMLDOMDocument并将其设置为类成员m_XMLDocumentClass,并从类中获取该类对象并将其设置为类成员m_XMLDocumentObject。 / p>

C ++代码

class JNIXMLDocument
{
    /* Constructor **/
    JNIXMLDocument()
    {
        /* Get JNI right version and set it. **/
        jint interface_id = JNI_VERSION_1_2;
        #ifdef JNI_VERSION_1_2
            interface_id = JNI_VERSION_1_2;
        #else
            interface_id = JNI_VERSION_1_1;
        #endif

        /* Trying to attach current thread. **/
        int res = g_JavaVirtualMachine->GetEnv(&m_JavaEnv, interface_id);
        if (res == JNI_EDETACHED || res == JNI_EVERSION) {
            res = g_JavaVirtualMachine->AttachCurrentThread(&m_JavaEnv, NULL);
        }

        /* Get Class from Java **/
        m_XMLDocumentClass = m_JavaEnv->FindClass("com/fido/android/framework/service/XMLDOMDocument");
        if (m_XMLDocumentClass != NULL) {
            /* Call java class constructor. **/
            jmethodID constructor = m_JavaEnv->GetMethodID(m_XMLDocumentClass , "<init>", "()V");
            m_XMLDocumentObject = m_JavaEnv->NewObject(m_XMLDocumentClass , constructor);    

        }

    }

    bool Initialize()
    {
        jmethodID method = m_JavaEnv->GetMethodID(m_XMLDocumentClass, "Initialize", "()Lorg/w3c/dom/Document;");
        jobject document = m_JavaEnv->CallObjectMethod(m_XMLDocumentObject , method);

    }

    private:
        JNIEnv* m_JavaEnv;
        jclass  m_XMLDocumentClass;
        jobject m_XMLDocumentObject;


};

C ++代码(正确的方法)

class JNIXMLDocument
{
    /* Constructor **/
    JNIXMLDocument()
    {
        /* Get JNI right version and set it. **/
        jint interface_id = JNI_VERSION_1_2;
        #ifdef JNI_VERSION_1_2
            interface_id = JNI_VERSION_1_2;
        #else
            interface_id = JNI_VERSION_1_1;
        #endif

        JNIEnv* env;
        /* Trying to attach current thread. **/
        int res = g_JavaVirtualMachine->GetEnv(&env, interface_id);
        if (res == JNI_EDETACHED || res == JNI_EVERSION) {
            res = g_JavaVirtualMachine->AttachCurrentThread(&env, NULL);
        }

        /* Get Class from Java **/
        jclass localClass = env->FindClass("com/fido/android/framework/service/XMLDOMDocument");
        if (localClass != NULL) {
            m_XMLDocumentClass = env->NewGlobalRef(localClass);
            /* Call java class constructor. **/
            jmethodID constructor = env->GetMethodID(localClass, "<init>", "()V");
            jobject localObject = env->NewObject(m_XMLDocumentClass , constructor);    
            m_XMLDocumentObject = env->NewGlobalRef(localObject );
        }

    }

    bool Initialize()
    {

    }

    private:
        jclass  m_XMLDocumentClass;
        jobject m_XMLDocumentObject;


};

问题

  1. 在构造函数中设置一次JNI接口指针(JNIEnv* m_JavaEnv)并在整个代码中使用它是正确的吗?
  2. 在构造函数中设置jclass m_XMLDocumentClass是否正确,而不是在所有方法中使用该变量?
  3. 以这种方式jobject m_XMLDocumentObject在构造函数中设置m_JavaEnv->NewObject(m_XMLDocumentClass , constructor);是否正确,或者我必须致电NewGlobalRef
  4. 如果我的应用程序不在同一个线程中(使用多个线程),会出现什么问题?

1 个答案:

答案 0 :(得分:3)

  

在构造函数中设置一次JNI接口指针(JNIEnv * m_JavaEnv)并在整个代码中使用它是正确的吗?

没有。它是特定于线程的。这就是Attach / DetachCurrentThread的用途。唯一可行的方法是在同一个线程中构造和销毁C ++对象。

  

在构造函数中设置jclass m_XMLDocumentClass是否正确,而不是在所有方法中使用该变量?

没有。它是一个本地引用,它在返回时获取的JNI方法到期。您必须另存为全局或弱引用,除非仅在单个JNI方法中使用。

Is it right to set jobject m_XMLDocumentObject in the constructor in this way m_JavaEnv->NewObject(m_XMLDocumentClass , constructor);

否:见上文。

  

或者我必须打电话给NewGlobalRef。

是的,如上所述。

  

如果我的应用程序不在同一个线程中(使用多个线程),会出现什么问题?

主要是JVM崩溃。 JVM假定您遵循JNI规范中的所有规则。那样做。