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中可以调用:
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);
}
分享到:
相关推荐
JNI提供了大量API用于在Java和C/C++之间交互,如创建和销毁Java对象、调用方法、访问字段、处理数组、异常处理等。例如: - `env->FindClass(className)`:查找Java类。 - `env->GetMethodID(cls, methodName, ...
通过以上详细的步骤和技术要点,我们可以看到,无论是Java调用C/C++还是C/C++调用Java,都需要仔细地处理数据类型转换、异常处理以及性能优化等问题。掌握这些技术细节,对于开发高效稳定的跨语言应用程序至关重要。
总的来说,理解和实现"C++ JNI多线程回调java"涉及到对JNI接口的深入理解,对多线程编程的掌握,以及对Java并发模型的认识。这是一个高级的跨语言编程话题,需要开发者具备扎实的C++和Java基础。在实际项目中,这样...
- **多线程支持**:JNI支持多线程,但需要注意线程安全问题,每个线程都有自己的JNIEnv指针。 - **异常处理**:Java中的异常可以由JNI代码触发,同时JNI也提供检查和抛出Java异常的机制。 - **64位支持**:确保...
描述中提到的“在JNI中用多线程调用Java对象”,意味着在C/C++代码中创建并管理多个线程,每个线程负责调用不同的Java方法或者处理不同的Java对象。在Android中,线程管理对于优化应用性能和避免UI阻塞至关重要。...
JNI在处理性能敏感的任务,如图形渲染、硬件访问或者与C/C++库集成时,尤其有用。本话题将深入探讨如何在Android中使用JNI进行多线程编程,并实现native方法对Java函数的回调。 1. **JNI基础知识**: - JNI是Java...
本文将深入探讨如何在JNI层实现多线程回调Java方法,以及如何解决在C/C++层多线程环境下findClass异常的问题。 首先,我们需要了解JNI的基本结构。在Java代码中,我们定义一个native方法,通过`System.loadLibrary...
Java调用C/C++的过程,通常被称为JNI(Java Native ...在实践中,还需要掌握JNI的各种数据类型映射、异常处理以及多线程同步等高级技巧。希望这个教程能为初学者提供一个良好的起点,进一步探索Java与C/C++之间的交互。
本示例主要讲解了如何在NDK中利用C++调用Java方法,并通过POSIX线程库实现多线程的生产者消费者模式。下面将详细阐述相关知识点。 1. **NDK与C++编程** NDK提供了一种在Android应用中集成原生代码的方式,使得...
在多线程环境中,当涉及到与本地代码(如C/C++)的交互时,同步机制显得尤为重要,以防止数据竞争和不一致的情况。本文将深入探讨如何使用JNI实现多线程同步,并通过源码来解析这一过程。 1. **JNI基础知识** JNI...
在Android开发中,有时我们需要利用C或C++的高性能特性,比如处理图形计算、音频处理等,这时就需要在Java和C/C++之间进行交叉调用。Android Studio支持这种跨语言调用,主要通过Android Native Development Kit ...
- 通过调整编译选项、内存管理和多线程等优化代码性能。 本压缩包中的"ndk代码"可能包含了一个示例项目,你可以通过研究其结构和代码来更好地理解上述过程。在实践中,了解NDK的JNI接口、内存管理、线程安全以及...
同时,JNI函数调用需要处理线程安全问题,特别是当多个线程同时访问Java对象时。 总的来说,C/C++调用Java的核心在于理解和正确使用JNI接口,确保Java和C/C++之间的数据转换正确,以及正确地管理JVM生命周期。这...
JNI在Android平台上扮演着桥梁的角色,使得开发者能够利用C/C++的强大性能和效率来处理计算密集型任务,同时保持Java的易用性和跨平台特性。 1. **JNI简介** - JNI是一种接口,让Java应用程序能够调用本地(非Java...
总之,实现"android JNI串口驱动支持多串口同时收发"涉及创建一个C/C++库来处理串口操作,编写JNI接口以在Java和C/C++之间进行通信,以及可能的多线程编程来确保并发处理。通过这种方式,Android应用可以高效地管理...
Java通过JNI(Java Native Interface)调用C语言函数库是一种常见的技术实践,它允许Java程序直接与本地操作系统和硬件交互,提高性能或者利用已有的C/C++代码库。本资料"Java通过JNI调用C语言函数库的方法.zip"提供...
1. **线程安全**:Java和C/C++运行在不同的线程中,因此在多线程环境下,需要处理好同步问题,避免数据竞争。 2. **异常处理**:在C/C++代码中调用Java方法时,可能抛出异常,需要适当地捕获并处理。 3. **内存管理*...
手册还提到了JNI编程中可能遇到的一些高级问题,例如异常处理和使用本地方法的多线程编程。JNI中的异常处理与Java中的异常处理有所不同,需要特别注意。多线程编程在JNI中涉及的是本地代码的线程,而这些线程与Java...
JNI在很多场景下都是必要的,比如当需要利用C/C++库来提高性能,或者实现与硬件设备的直接通信时。本示例中,我们将深入探讨如何使用JNI实现回调机制以及在JNI中开启线程。 1. **JNI回调JAVA的函数**: 在Java中,...
在Java编程环境中,有时我们需要利用C或C++的高性能特性,这时可以借助Java Native Interface (JNI) 进行Java和C++之间的交互调用。JNI允许Java代码调用本地(非Java)代码,并且反之亦然。下面我们将详细介绍如何用...