当JNI遇到多线程--java对象如何被C++中的多个线程访问?
2012-12-23 11:39
459 查看
java中要访问C++代码时, 使用JNI是唯一选择. 然而,在多线程的情况下, 可能出现以下问题:
问题描述:
一个java对象通过JNI调用DLL中一个send()函数向服务器发送消息,不等服务器消息到来就立即返回.同时
把JNI接口的指针JNIEnv *env,和jobject obj保存在DLL中的变量里.
一段时间后,DLL中的消息接收线程接收到服务器发来的消息,
并试图通过保存过的env和obj来调用先前的java对象的方法来处理此消息.
然而,JNI文档上说,JNI接口的指针JNIEnv*不能在c++的线程间共享,
在我的程序中,如果接收线程试图调用java对象的方法,程序会突然退出.
不知道有没有方法突破JNI接口的指针不能在多个c++线程中共享的限制?
解决办法:
在 http://java.sun.com/docs/books/jni/html/pitfalls.html#29161 提到,
JNI接口指针不可为多个线程共用,但是java虚拟机的JavaVM指针是整个jvm公用的. 于是,在DLL中可以调用:
来将DLL中的线程 "attached to the virtual machine"(不知如何翻译...),同时获得了这个线程在jvm中的 JNIEnv指针.
由于我需要做的是在DLL中的一个线程里改变某个java对象的值,所以,还必须获取那个java对象的jobject指针.同 JNIEnv 指针一样,jobject指针也不能在多个线程中共享. 就是说,不能直接在保存一个线程中的jobject指针到全局变量中,然后在另外一个线程中使用它.幸运的是,可以用
gs_object=env->NewGlobalRef(obj);
来将传入的obj保存到gs_object中,从而其他线程可以使用这个gs_object来操纵那个java对象了.
示例代码如下:
(1)
(2)
问题描述:
一个java对象通过JNI调用DLL中一个send()函数向服务器发送消息,不等服务器消息到来就立即返回.同时
把JNI接口的指针JNIEnv *env,和jobject obj保存在DLL中的变量里.
一段时间后,DLL中的消息接收线程接收到服务器发来的消息,
并试图通过保存过的env和obj来调用先前的java对象的方法来处理此消息.
然而,JNI文档上说,JNI接口的指针JNIEnv*不能在c++的线程间共享,
在我的程序中,如果接收线程试图调用java对象的方法,程序会突然退出.
不知道有没有方法突破JNI接口的指针不能在多个c++线程中共享的限制?
解决办法:
在 http://java.sun.com/docs/books/jni/html/pitfalls.html#29161 提到,
JNI接口指针不可为多个线程共用,但是java虚拟机的JavaVM指针是整个jvm公用的. 于是,在DLL中可以调用:
static JavaVM* gs_jvm; env->GetJavaVM(&gs_jvm); //来获取JavaVM指针.获取了这个指针后,在DLL中的另一个线程里,可以调用: JNIEnv *env; gs_jvm->AttachCurrentThread((void **)&env, NULL);
来将DLL中的线程 "attached to the virtual machine"(不知如何翻译...),同时获得了这个线程在jvm中的 JNIEnv指针.
由于我需要做的是在DLL中的一个线程里改变某个java对象的值,所以,还必须获取那个java对象的jobject指针.同 JNIEnv 指针一样,jobject指针也不能在多个线程中共享. 就是说,不能直接在保存一个线程中的jobject指针到全局变量中,然后在另外一个线程中使用它.幸运的是,可以用
gs_object=env->NewGlobalRef(obj);
来将传入的obj保存到gs_object中,从而其他线程可以使用这个gs_object来操纵那个java对象了.
示例代码如下:
(1)
//java代码:Test.java: import java.io.*; class Test implements Runnable { public int value = 0; private Thread tx=null; public Test() { tx=new Thread(this,"tx"); } static { System.loadLibrary("Test"); } public native void setEnev(); public static void main(String args[]) { Test t = new Test(); t.setEnev(); System.out.println("ok in java main"); t.tx.start(); try { Thread.sleep(10000000); }catch(Exception e) { System.out.println("error in main"); } } public void run() { try { while(true) { Thread.sleep(1000); System.out.println(value); } }catch(Exception e) { System.out.println("error in run"); } } }
(2)
//DLL代码:Test.cpp: #include "test.h" #include<windows.h> #include<stdio.h> static JavaVM *gs_jvm=NULL; static jobject gs_object=NULL; static int gs_i=10; void WINAPI ThreadFun(PVOID argv) { JNIEnv *env; gs_jvm->AttachCurrentThread((void **)&env, NULL); jclass cls = env->GetObjectClass(gs_object); jfieldID fieldPtr = env->GetFieldID(cls,"value","I"); while(1) { Sleep(100); //在DLL中改变外面的java对象的value变量的值. env->SetIntField(gs_object,fieldPtr,(jint)gs_i++); } } JNIEXPORT void JNICALL Java_Test_setEnev(JNIEnv *env, jobject obj) { printf("come into test.dll/n"); //Returns “0” on success; returns a negative value on failure. int retGvm=env->GetJavaVM(&gs_jvm); //直接保存obj到DLL中的全局变量是不行的,应该调用以下函数: gs_object=env->NewGlobalRef(obj); HANDLE ht=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ThreadFun,0,NULL,NULL); printf("the Handle ht is:%d/n",ht); }
相关文章推荐
- chap 17:当JNI遇到多线程--java对象如何被C++中的多个线程访问?
- 当JNI遇到多线程--java对象如何被C++中的多个线程访问?
- 当JNI遇到多线程--java对象如何被C++中的多个线程访问?
- 当JNI遇到多线程--java对象如何被C++中的多个线程访问?
- java多线程与线程并发五:多个线程访问共享对象和数据的方式
- JNI中在被调用的C/C++函数中如何访问Java程序中的类,并编写应用实例
- JNI中如何在C++文件中调用java中的对象,举例说明
- Android JNI中Java与C++对象如何建立一一对应的关系
- java多线程学习-多个线程访问对象共享数据的方式
- java多线程之多个线程访问共享对象和数据的方式
- Java多线程编程核心技术---对象及变量的并发访问
- 2 通过JNI混合使用Java和C++ -----> 访问数组
- JNI中反向访问Java对象
- C++中的线程函数如何访问类中的成员变量
- 【转】WPF [调用线程无法访问此对象,因为另一个线程拥有该对象。] 解决方案以及如何实现字体颜色的渐变
- [java多线程]如何安全的退出线程
- JAVA多线程-对象及变量的并发访问(一)synchronized详解
- Java线程和多线程(二)——对象中的wait,notify以及notifyAll方法
- JNI学习笔记(四)JNI中本地语言创建Java对象并且访问具体方法(附例子)
- 二、java多线程编程核心技术之(笔记)——如何停止线程?