当JNI遇到多线程--java对象如何被C++中的多个线程访问?

举报
ShaderJoy 发表于 2021/12/29 23:18:06 2021/12/29
【摘要】 java中要访问C++代码时, 使用JNI是唯一选择. 然而,在多线程的情况下, 可能出现以下问题: 问题描述: 一个java对象通过JNI调用DLL中一个send()函数向服务器发送消息,不等服务器消息到来就立即返回.同时 把JNI接口的指针JNIEnv *env,和jobject obj保存在DLL中的变量里. 一段时间后,...

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中可以调用:


  
  1. static JavaVM* gs_jvm;
  2. env->GetJavaVM(&gs_jvm); //来获取JavaVM指针.获取了这个指针后,在DLL中的另一个线程里,可以调用:
  3. JNIEnv *env;
  4. gs_jvm->AttachCurrentThread((void **)&env, NULL);







(1)


  
  1. //java代码:Test.java:
  2. import java.io.*;
  3. class Test implements Runnable
  4. {
  5. public int value = 0;
  6. private Thread tx=null;
  7. public Test()
  8. {
  9. tx=new Thread(this,"tx");
  10. }
  11. static
  12. {
  13. System.loadLibrary("Test");
  14. }
  15. public native void setEnev();
  16. public static void main(String args[])
  17. {
  18. Test t = new Test();
  19. t.setEnev();
  20. System.out.println("ok in java main");
  21. t.tx.start();
  22. try
  23. {
  24. Thread.sleep(10000000);
  25. }catch(Exception e)
  26. {
  27. System.out.println("error in main");
  28. }
  29. }
  30. public void run()
  31. {
  32. try
  33. {
  34. while(true)
  35. {
  36. Thread.sleep(1000);
  37. System.out.println(value);
  38. }
  39. }catch(Exception e)
  40. {
  41. System.out.println("error in run");
  42. }
  43. }
  44. }

(2) 


  
  1. //DLL代码:Test.cpp:
  2. #include "test.h"
  3. #include<windows.h>
  4. #include<stdio.h>
  5. static JavaVM *gs_jvm=NULL;
  6. static jobject gs_object=NULL;
  7. static int gs_i=10;
  8. void WINAPI ThreadFun(PVOID argv)
  9. {
  10. JNIEnv *env;
  11. gs_jvm->AttachCurrentThread((void **)&env, NULL);
  12. jclass cls = env->GetObjectClass(gs_object);
  13. jfieldID fieldPtr = env->GetFieldID(cls,"value","I");
  14. while(1)
  15. {
  16. Sleep(100);
  17. //在DLL中改变外面的java对象的value变量的值.
  18. env->SetIntField(gs_object,fieldPtr,(jint)gs_i++);
  19. }
  20. }
  21. JNIEXPORT void JNICALL Java_Test_setEnev(JNIEnv *env, jobject obj)
  22. {
  23. printf("come into test.dll/n");
  24. //Returns “0” on success; returns a negative value on failure.
  25. int retGvm=env->GetJavaVM(&gs_jvm);
  26. //直接保存obj到DLL中的全局变量是不行的,应该调用以下函数:
  27. gs_object=env->NewGlobalRef(obj);
  28. HANDLE ht=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ThreadFun,0,NULL,NULL);
  29. printf("the Handle ht is:%d/n",ht);
  30. }

文章来源: panda1234lee.blog.csdn.net,作者:panda1234lee,版权归原作者所有,如需转载,请联系作者。

原文链接:panda1234lee.blog.csdn.net/article/details/8393017

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。