`
marb
  • 浏览: 422520 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

jni和c/c++多线程的处理

阅读更多

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);
}

分享到:
评论

相关推荐

    使用C/C++实现Java的Native方法接口(JNI)/ JNI编程(C/C++) 代码实例

    JNI提供了大量API用于在Java和C/C++之间交互,如创建和销毁Java对象、调用方法、访问字段、处理数组、异常处理等。例如: - `env-&gt;FindClass(className)`:查找Java类。 - `env-&gt;GetMethodID(cls, methodName, ...

    JNI技术手册 c/c++调用java

    通过以上详细的步骤和技术要点,我们可以看到,无论是Java调用C/C++还是C/C++调用Java,都需要仔细地处理数据类型转换、异常处理以及性能优化等问题。掌握这些技术细节,对于开发高效稳定的跨语言应用程序至关重要。

    C++JNI多线程回调java

    总的来说,理解和实现"C++ JNI多线程回调java"涉及到对JNI接口的深入理解,对多线程编程的掌握,以及对Java并发模型的认识。这是一个高级的跨语言编程话题,需要开发者具备扎实的C++和Java基础。在实际项目中,这样...

    JNI 教程 java与c/c++互相调用

    - **多线程支持**:JNI支持多线程,但需要注意线程安全问题,每个线程都有自己的JNIEnv指针。 - **异常处理**:Java中的异常可以由JNI代码触发,同时JNI也提供检查和抛出Java异常的机制。 - **64位支持**:确保...

    jni中用多线程调用java代码

    描述中提到的“在JNI中用多线程调用Java对象”,意味着在C/C++代码中创建并管理多个线程,每个线程负责调用不同的Java方法或者处理不同的Java对象。在Android中,线程管理对于优化应用性能和避免UI阻塞至关重要。...

    Android JNI多线程编程回调JAVA函数

    JNI在处理性能敏感的任务,如图形渲染、硬件访问或者与C/C++库集成时,尤其有用。本话题将深入探讨如何在Android中使用JNI进行多线程编程,并实现native方法对Java函数的回调。 1. **JNI基础知识**: - JNI是Java...

    轻松学会JNI层多线程回调java方法

    本文将深入探讨如何在JNI层实现多线程回调Java方法,以及如何解决在C/C++层多线程环境下findClass异常的问题。 首先,我们需要了解JNI的基本结构。在Java代码中,我们定义一个native方法,通过`System.loadLibrary...

    java调用C/C++过程

    Java调用C/C++的过程,通常被称为JNI(Java Native ...在实践中,还需要掌握JNI的各种数据类型映射、异常处理以及多线程同步等高级技巧。希望这个教程能为初学者提供一个良好的起点,进一步探索Java与C/C++之间的交互。

    NDK中C++使用POSIX线程库调用java

    本示例主要讲解了如何在NDK中利用C++调用Java方法,并通过POSIX线程库实现多线程的生产者消费者模式。下面将详细阐述相关知识点。 1. **NDK与C++编程** NDK提供了一种在Android应用中集成原生代码的方式,使得...

    JNI 多线程同步机制的源码实现

    在多线程环境中,当涉及到与本地代码(如C/C++)的交互时,同步机制显得尤为重要,以防止数据竞争和不一致的情况。本文将深入探讨如何使用JNI实现多线程同步,并通过源码来解析这一过程。 1. **JNI基础知识** JNI...

    android studio项目java C/C++ 相互调用

    在Android开发中,有时我们需要利用C或C++的高性能特性,比如处理图形计算、音频处理等,这时就需要在Java和C/C++之间进行交叉调用。Android Studio支持这种跨语言调用,主要通过Android Native Development Kit ...

    ndk源码基于eclipse开发c/c++/java

    - 通过调整编译选项、内存管理和多线程等优化代码性能。 本压缩包中的"ndk代码"可能包含了一个示例项目,你可以通过研究其结构和代码来更好地理解上述过程。在实践中,了解NDK的JNI接口、内存管理、线程安全以及...

    在 C/C++ 中调用 Java

    同时,JNI函数调用需要处理线程安全问题,特别是当多个线程同时访问Java对象时。 总的来说,C/C++调用Java的核心在于理解和正确使用JNI接口,确保Java和C/C++之间的数据转换正确,以及正确地管理JVM生命周期。这...

    androidjni编程,java和c层的互相通信传递数据

    JNI在Android平台上扮演着桥梁的角色,使得开发者能够利用C/C++的强大性能和效率来处理计算密集型任务,同时保持Java的易用性和跨平台特性。 1. **JNI简介** - JNI是一种接口,让Java应用程序能够调用本地(非Java...

    android JNI串口驱动支持多串口同时收发

    总之,实现"android JNI串口驱动支持多串口同时收发"涉及创建一个C/C++库来处理串口操作,编写JNI接口以在Java和C/C++之间进行通信,以及可能的多线程编程来确保并发处理。通过这种方式,Android应用可以高效地管理...

    Java通过JNI调用C语言函数库的方法.zip

    Java通过JNI(Java Native Interface)调用C语言函数库是一种常见的技术实践,它允许Java程序直接与本地操作系统和硬件交互,提高性能或者利用已有的C/C++代码库。本资料"Java通过JNI调用C语言函数库的方法.zip"提供...

    JNI 回调函数 Callback

    1. **线程安全**:Java和C/C++运行在不同的线程中,因此在多线程环境下,需要处理好同步问题,避免数据竞争。 2. **异常处理**:在C/C++代码中调用Java方法时,可能抛出异常,需要适当地捕获并处理。 3. **内存管理*...

    Java_programming_with_JNI

    手册还提到了JNI编程中可能遇到的一些高级问题,例如异常处理和使用本地方法的多线程编程。JNI中的异常处理与Java中的异常处理有所不同,需要特别注意。多线程编程在JNI中涉及的是本地代码的线程,而这些线程与Java...

    JNI实现回调及JNI开启线程

    JNI在很多场景下都是必要的,比如当需要利用C/C++库来提高性能,或者实现与硬件设备的直接通信时。本示例中,我们将深入探讨如何使用JNI实现回调机制以及在JNI中开启线程。 1. **JNI回调JAVA的函数**: 在Java中,...

    用JNI实现java和C++的相互调用

    在Java编程环境中,有时我们需要利用C或C++的高性能特性,这时可以借助Java Native Interface (JNI) 进行Java和C++之间的交互调用。JNI允许Java代码调用本地(非Java)代码,并且反之亦然。下面我们将详细介绍如何用...

Global site tag (gtag.js) - Google Analytics