java 与jni线程_JNI(Java Native Interface)在多线程中的运用_weixin_39711959的博客-程序员宅基地

技术标签: java 与jni线程  

我在这里将文章整理了一下,重新修改了部分描述和增加了一些重要的说明事项。修改文如下:

问题描述:

一个java对象通过JNI调用DLL中一个send()函数向服务器发送消息,不等服务器消息到来就立即返回,同时把JNI接口的指针JNIEnv *env(虚拟机环境指针),和jobject obj保存在DLL中的变量里.

一段时间后,DLL中的消息接收线程接收到服务器发来的消息,并试图通过保存过的env和obj来调用先前的java对象的方法(相当于JAVA回调方法)来处理此消息.此时程序会突然退出(崩溃).

解决办法:

解决此问题首先要明白造成这个问题的原因。那么崩溃的原因是什么呢?

JNI文档上有明确表述

The JNIEnv pointer, passed as the first argument to every native method, can only be used in the thread with which it is associated. It is wrong to cache the JNIEnv interface pointer obtained from one thread, and use that pointer in another thread.

意思就是JNIEnv指针不能直接在多线程中共享使用。上面描述的程序崩溃的原因就在这里:回调时的线程和之前保存变量的线程共享了这个JNIEnv *env指针和jobject obj变量。

,

JNIEnv *env指针不可为多个线程共用,但是java虚拟机的JavaVM指针是整个jvm公用的,我们可以通过JavaVM来得到当前线程的JNIEnv指针.

于是,在第一个线程A中调用:

JavaVM* gs_jvm;

env->GetJavaVM(&gs_jvm); //来获取JavaVM指针.获取了这个指针后,将该JavaVM保存起来。

在另一个线程B里,调用

JNIEnv *env;

gs_jvm->AttachCurrentThread((void **)&env, NULL);

这里还必须获取那个java对象的jobject指针,因为我们要回调JAVA方法.同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;

static{ System.loadLibrary("Test");}

public native void setEnev();//本地方法

public static void main(String args[]) throws Exception

{

Test t = new Test();

t.setEnev(); //调用本地方法

while(true)

{

Thread.sleep(1000);

System.out.println(t.value);

}

}

}

(2) DLL代码:Test.cpp:

#include "test.h"

#include

#include

static JavaVM *gs_jvm=NULL;

static jobject gs_object=NULL;

static int gs_i=10;

JNIEXPORT void JNICALL Java_Test_setEnev(JNIEnv *env, jobject obj)

{

env->GetJavaVM(&gs_jvm); //保存到全局变量中JVM

//直接赋值obj到DLL中的全局变量是不行的,应该调用以下函数:

gs_object=env->NewGlobalRef(obj);

HANDLE ht=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ThreadFun,0,NULL,NULL);

}

void WINAPI ThreadFun(PVOID argv)//JNI中线程回调这个方法

{

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

//这里改变JAVA对象的属性值(回调JAVA)

env->SetIntField(gs_object,fieldPtr,(jint)gs_i++);

}

}

JNI限制:

There are certain constraints that you must keep in mind when writing native methods that are to run in a multithreaded environment. By understanding and programming within these constraints, your native methods will execute safely no matter how many threads simultaneously execute a given native method. For example:

AJNIEnvpointer is only valid in the thread associated with it. You must not pass this pointer from one thread to another, or cache and use it in multiple threads. The Java virtual machine passes a native method the sameJNIEnvpointer in consecutive invocations from the same thread, but passes differentJNIEnvpointers when invoking that native method from different threads. Avoid the common mistake of caching theJNIEnvpointer of one thread and using the pointer in another thread.

Local referencesare valid only in the thread that created them. You must not pass local references from one thread to another. You should always convert local references to global references whenever there is a possibility that multiple threads may use the same reference.

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_39711959/article/details/114065115

智能推荐

java 奖xls转成csv_Java操作Excel文件以及将xls/xlsx转为csv文件_weixin_39970855的博客-程序员宅基地

JAVA EXCEL API:是一开放源码项目,通过它Java开发人员可以读取Excel文件的内容、创建新的Excel文件、更新已经存在的Excel文件。通过引入JXL.jar库后可以很方便地对xls或者xlsx文件进行读写操作,下面简要示例对xls文件的读取:try {String fileName = "yourPath/datas.xls";File file = new File(file...

linux公社mysql流程图_在Linux系统安装MySql步骤截图详解_王王介的博客-程序员宅基地

如下是我工作中的记录,介绍的是linux系统下使用官方编译好的二进制文件进行安装MySql的安装过程和安装截屏,这种安装方式速度快,安装步骤简单!需要的朋友可以按照如下步骤进行安装,可以快速安装MySql,希望可以帮助大家:)!1、下载mysql的linux版本的二进制安装包:这里我将安装包重命名为:tingyun-mysql-5.6.22.tar.gz说明:根据自己需要可以不进行重命名操作2、解...

计算机2级这么个考法,计算机二级考试备考方法_PivotEdu中枢教育的博客-程序员宅基地

该如何备考计算机二级考试呢,下面小编为大家介绍关于计算机二级考试的备考方法,欢迎大家阅读!计算机二级考试备考方法一、设定考试倒计时目前看起来倒计时的数字还很可观,似乎是时间充足,然而换算一下的话,就不那么充足了。因为每个科目需要复习的知识点比较多,而且需要将这些知识点理解透彻还需要更多的时间,加上每天的倒计时,这时就会让我们更加珍惜计算机二级备考时间。二、形成稳定的生物钟要进入计算机二级备考状态,...

脉冲耦合神经网络(PCNN)阅读笔记_262416的博客-程序员宅基地_脉冲耦合神经网络

摘要本文采用高级视觉模型来描述灵长类视觉系统中的信息传递和连接。信息链接方案,如状态相关模块化和时间同步,被视为视觉系统使用期望组合信息的方法,以填充缺失信息和删除不需要的信息。研究了使用基于生理学理论模型的链接方法结合当前图像处理技术进行模式识别的可能性。这些图像处理技术是变换,例如(但不限于)小波滤波器、命中或未命中滤波器、形态滤波器和高斯差分滤波器。选择这些特殊的过滤器是因为它们模拟灵长类视觉系统中执行的功能。为了实现生理激励的连接方法,选择脉冲耦合神经网络(PCNN)作为视觉模型的基本构建块,在

ubuntu php postgresql,Ubuntu系统如何启动PostgreSQL数据库_weixin_39587822的博客-程序员宅基地

要修改的文件是postgresql.conf,该文件在/etc/postgresql/8.3/main/目录下。把#listen_address='localhost'改成listen_address='*'这就启动了监听,能够让外部程序连接进来。其次要修改gp_hba.conf,也在/etc/postgresql/8.3/main/目录下。我由于不需要太多的身份认证,所以把md5都改成trust...

JUC同步锁: CyclicBarrier 代码Demo_quokka_1009的博客-程序员宅基地

说明: new CyclicBarrier(20); -> 满20个线程 运行一次 不满不停场景: 比如一个线程redis 一个线程mysql ... 都执行完后做后面的操作 复杂操作: 1: 数据库 2: 网络 3: 文件 并发执行: 线程 - 操作 线程 - 操作 import java.util.concurrent.BrokenBarrierException;import java.util.concurrent.CyclicBarrier;

随便推点

DOM BOM document window 区别_普通网友的博客-程序员宅基地

DOM 是为了操作文档出现的 API,document 是其的一个对象; BOM 是为了操作浏览器出现的 API,window 是其的一个对象。 使用下图讲解: 归DOM管的: E区:即doc...

linux操作系统基础与实训教程,清华大学出版社-图书详情-《Linux操作系统基础与实训教程》..._weixin_39765697的博客-程序员宅基地

前 言随着计算机技术的不断发展,越来越多的用户认识到Linux的优点。作为唯一一款与微软Windows竞争的桌面操作系统,Linux逐渐受到用户的重视;并且随着其在市场中占有量的稳步提高,已经有越来越多的用户希望掌握该系统的操作。本书是专门为初级用户编写的一本Linux入门级的图书,本书以Fedora 8.0操作系统为基础,循序渐进地介绍了Linux的基础知识和操作技巧,既注重对理论知识和基...

JavaScript随笔——函数_Layznana的博客-程序员宅基地

高阶函数定义函数传入另一个函数作为参数常用高阶函数map()调用:ArrayName.map ( FunctionName_f )返回值:数组 [ f(arr[0]), f(arr[1]),f(arr[2]),…]reduce()调用: ArrayName.reduce ( FunctionName_f )返回值:一个数值例子:var arr = [1,2,3,4]var result = arr.reduce(function(x,y){ return x+y;}); //r

Oracle创建employee表,oracle之创建和管理表之练习题_weixin_39766910的博客-程序员宅基地

51. 利用子查询创建表 myemp,该表中包含 employees 表的 employee_id(id), last_name(name), salary(sal), email 字段1). 创建表的同时复制 employees 对应的记录create table myempasselect employee_id id, last_name name, salary sal, email fr...

git 合并分支出现 Please enter a commit message to explain why this merge is necessary;# especially if it_xingxingxingge的博客-程序员宅基地

git 在pull或者合并分支的时候有时会遇到这个界面1丶按键盘左上角"Esc"2丶输入":wq",注意是冒号+wq,按回车键即可

互联网运营面试题_一道经典面试:你认为互联网运营是做什么的?_weixin_39614528的博客-程序员宅基地

成长之“道”写得差不多了,从这篇开始以后多写写“术”。今天的主题是一道经典面试:你觉得互联网运营是做什么的?相信不少读者都遇到过类似的问题,比如你觉得游戏运营是做什么的?你觉得产品经理是做什么的?等等。这道题目一般是针对应届生或者工作1年左右经验的人,我从招聘者和应聘者两个角度来分析这个问题:01、招聘者对于招聘者来说,主要有两个目的:快速过滤非目标人选应届生和工作1年左右的人,可能对岗位完全没什...

推荐文章

热门文章

相关标签