正确的方式在多线程应用程序使用JNI工作 [英] Right way to work with JNI in multithreading application
问题描述
描述
在我的C ++应用程序类 JNIXMLDocument
这让一些JAVA方法调用。在 JNIXMLDocument
的构造函数I类附着当前线程,并将其设置为我的类成员的JNIEnv * m_JavaEnv
,然后用它在所有的方法。另外在构造函数中,我试图找到我的Java类 COM /菲/安卓/框架/服务/ XMLDOMDocument
键,将其设置为类成员 m_XMLDocumentClass
,也得到了类,类对象并将其设置为类成员 m_XMLDocumentObject
。
C ++ code
类JNIXMLDocument
{
/ * **构造函数/
JNIXMLDocument()
{
/ *获取JNI正确的版本并进行设置。 ** /
jint interface_id = JNI_VERSION_1_2;
#IFDEF JNI_VERSION_1_2
interface_id = JNI_VERSION_1_2;
#其他
interface_id = JNI_VERSION_1_1;
#万一 / *试图连接当前线程。 ** /
INT解析度= g_JavaVirtualMachine-> GETENV(安培; m_JavaEnv,interface_id);
如果(RES == || JNI_EDETACHED资源== JNI_EVERSION){
RES = g_JavaVirtualMachine-> AttachCurrentThread(安培; m_JavaEnv,NULL);
} / *从Java类获得** /
m_XMLDocumentClass = m_JavaEnv->的findClass(COM /菲/安卓/框架/服务/ XMLDOMDocument);
如果(m_XMLDocumentClass!= NULL){
/ *调用Java类的构造函数。 ** /
jmethodID构造= m_JavaEnv->的GetMethodID(m_XMLDocumentClass,&所述;初始化>中,()V);
m_XMLDocumentObject = m_JavaEnv-> NewObject的(m_XMLDocumentClass,构造函数); } } 布尔初始化()
{
jmethodID方法= m_JavaEnv->的GetMethodID(m_XMLDocumentClass,初始化,()Lorg / W3C / DOM /文件;);
jobject文件= m_JavaEnv-> CallObjectMethod(m_XMLDocumentObject,法); } 私人的:
JNIEnv的* m_JavaEnv;
JCLASS m_XMLDocumentClass;
jobject m_XMLDocumentObject;
};
C ++ code(正道)
类JNIXMLDocument
{
/ * **构造函数/
JNIXMLDocument()
{
/ *获取JNI正确的版本并进行设置。 ** /
jint interface_id = JNI_VERSION_1_2;
#IFDEF JNI_VERSION_1_2
interface_id = JNI_VERSION_1_2;
#其他
interface_id = JNI_VERSION_1_1;
#万一 JNIEnv的* ENV;
/ *试图连接当前线程。 ** /
INT解析度= g_JavaVirtualMachine-> GETENV(安培; ENV,interface_id);
如果(RES == || JNI_EDETACHED资源== JNI_EVERSION){
RES = g_JavaVirtualMachine-> AttachCurrentThread(安培; ENV,NULL);
} / *从Java类获得** /
JCLASS localClass = env->的findClass(COM /菲/安卓/框架/服务/ XMLDOMDocument);
如果(localClass!= NULL){
m_XMLDocumentClass = env-> NewGlobalRef(localClass);
/ *调用Java类的构造函数。 ** /
jmethodID构造= env->的GetMethodID(localClass,&所述;初始化>中,()V);
jobject localObject = env-> NewObject的(m_XMLDocumentClass,构造函数);
m_XMLDocumentObject = env-> NewGlobalRef(localObject);
} } 布尔初始化()
{ } 私人的:
JCLASS m_XMLDocumentClass;
jobject m_XMLDocumentObject;
};
问题
- 是不是正确的设置JNI接口指针(
的JNIEnv * m_JavaEnv
)在构造函数中一次,在整个code使用它? - 是正确设置
JCLASS m_XMLDocumentClass
在构造函数和比使用该变量中的所有方法? - 是正确设置
jobject m_XMLDocumentObject
以这种方式构造m_JavaEnv-> NewObject的(m_XMLDocumentClass,构造函数);
也许我必须调用NewGlobalRef
。 - 可以出现什么问题,如果不是在同一个线程我的应用程序的工作(使用多个线程)?
是不是在构造函数中设置JNI接口指针(JNIEnv的* m_JavaEnv)一次,在整个code使用它?
块引用>没有。它是线程特定。这就是附加/ DetachCurrentThread是。这可以工作的唯一方法是,如果C ++对象被创建,并在同一个线程销毁。
时的正确设置JCLASS m_XMLDocumentClass在构造函数和比使用该变量中的所有方法?
块引用>没有。它是一个本地参考,并且当JNI方法它返回被收购过期。你必须保存为一个全球性或弱引用的除非的它只是将是一个单一的JNI方法中使用。
是否正确设置jobject m_XMLDocumentObject在构造函数中以这种方式m_JavaEnv-> NewObject的(m_XMLDocumentClass,构造函数);
块引用>没有。见上面
也许我必须调用NewGlobalRef。
块引用>是的,正如上面。
有什么问题可以出现,如果在同一个线程我的应用程序不工作(使用多个线程)?
块引用>主要是JVM崩溃。在JVM假定您按照JNI规范所有规则。这样做的。
Description
In my C++ application class
JNIXMLDocument
which made some JAVA method calls. In the constructor ofJNIXMLDocument
class I attach current thread and set it to my class memberJNIEnv* m_JavaEnv
and then use it in all methods. Also in the constructor I am trying to find my JAVA classcom/fido/android/framework/service/XMLDOMDocument
and set it to class memberm_XMLDocumentClass
and also get that class object from the class and set it to class memberm_XMLDocumentObject
.C++ Code
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++ Code (Right way)
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; };
Questions
- Is it right to set JNI interface pointer (
JNIEnv* m_JavaEnv
) in the constructor once and use it in the whole code ?- Is it right to set
jclass m_XMLDocumentClass
in the constructor and than use that variable in the all methods ?- Is it right to set
jobject m_XMLDocumentObject
in the constructor in this waym_JavaEnv->NewObject(m_XMLDocumentClass , constructor);
or maybe I must callNewGlobalRef
.- What problems can appear if my application work not in the same thread (use many threads) ?
解决方案Is it right to set JNI interface pointer (JNIEnv* m_JavaEnv) in the constructor once and use it in the whole code ?
No. It is thread-specific. That's what Attach/DetachCurrentThread are for. The only way this can work is if the C++ object is constructed and destroyed in the same thread.
Is it right to set jclass m_XMLDocumentClass in the constructor and than use that variable in the all methods ?
No. It is a local reference, and it expires when the JNI method it was acquired in returns. You must save as a global or weak reference unless it is only going to be used within a single JNI method.
Is it right to set jobject m_XMLDocumentObject in the constructor in this way m_JavaEnv->NewObject(m_XMLDocumentClass , constructor);
No: see above.
or maybe I must call NewGlobalRef.
Yes, as above.
What problems can appear if my application work not in the same thread (use many threads) ?
Mainly JVM crashes. The JVM assumes you follow all the rules in the JNI specification. So do that.
这篇关于正确的方式在多线程应用程序使用JNI工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!