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

描述

在我的C ++应用程序类JNIXMLDocument中进行了一些JAVA方法调用。 在JNIXMLDocument类的构造函数中,我附加当前线程并将其设置为我的类成员JNIEnv* m_JavaEnv ,然后在所有方法中使用它。 同样在构造函数中,我试图找到我的JAVA类com/fido/android/framework/service/XMLDOMDocument并将其设置为类成员m_XMLDocumentClass并从类中获取该类对象并将其设置为类成员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 /* 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 , "", "()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, "", "()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. 如果我的应用程序不在同一个线程中(使用多个线程),会出现什么问题?

在构造函数中设置一次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规范中的所有规则。 那样做吧。