JNI官方规范中文版——在程序中集成JVM需要注意的JNI特征 翻译

我们已经讨论了JNI在写本地代码和向本地应用程序中集成JVM时的特征。本章接下来的部分分介绍其它的JNI特征。

8.1 JNI和线程

JVM可以做到在相同的地址空间内执行多个线程。由于多个线程可能会在同时共享资源,所以,增加了程序的复杂性。

要完全理解本章的东西,你需要对多线程编程比较熟悉,知道怎么样在JAVA中用多线程访问共享资源。

8.1.1 约束限制

如果你的本地代码要运行在多个线程中,有一些约束条件需要注意,这样的话,才能使得你的本地代码无论被多少个线程同时运行,都不会出现问题。

1、 JNIEnv指针只在它所在的线程中有效,不能跨线程传递和使用。不同线程调用一个本地方法时,传入的JNIEnv指针是不同的。

2、 局部引用只在创建它们的线程中有效,同样不能跨线程传递。但可以把局部引用转化成全局引用来供多线程使用。

8.1.2 监视器的入口和出口

监视器是JAVA平台的基本同步机制。每一个对象都可以和一个监视器绑定:

synchronized (obj) {

... // synchronized block

}

本地代码中可以通过调用JNI函数来达到与上述JAVA代码中等效的同步目的。这要用到两个JNI函数:MonitorEnter负责进入同步块,MonitorExit用来函数同步块。

if ((*env)->MonitorEnter(env, obj) != JNI_OK) {

... /* error handling */

}

... /* synchronized block */

if ((*env)->MonitorExit(env, obj) != JNI_OK) {

... /* error handling */

};

运行上面这段代码时,线程必须先进入obj的监视器,再执行同步块中的代码。MonitorEnter需要传入jobject作为参数。同时,如果另一个线程已经进入了这个与jobject监视器的话,当前线程会阻塞。如果当前线程在不拥有监视器的情况下调用MonitorExit的话,会产生一个错误,并抛出一个IllegalMonitorStateException异常。上面的代码中包含了MonitorEnter和MonitorExit这对函数的调用,在这对函数的使用时,我们一定要注意错误检查,因为这对函数有可能执行失败(比如,建立监视器的资源分配不成功等原因)。这对函数可以工作在jclass、jstring、jarray等类型上面,这些类型的共同特征是,都是jobject引用的特殊类型

有一个MonitorEnter方法,一定也要有一个与之对应的MonitorExit方法。尤其是在有错误或者异常需要处理的地方,要尤其小心。

if ((*env)->MonitorEnter(env, obj) != JNI_OK) ...;

...

if ((*env)->ExceptionOccurred(env)) {

... /* exception handling */

/* remember to call MonitorExit here */

if ((*env)->MonitorExit(env, obj) != JNI_OK) ...;

}

... /* Normal execution path.

if ((*env)->MonitorExit(env, obj) != JNI_OK) ...;

调用MonitorEnter而不调用MonitorExit的话,很可能会引起死锁。通过上面这段代码和本节开始时的JAVA代码的比较,你一定能发现用JAVA来进行同步要方便的多,所以,尽量用JAVA来做同步吧,把与同步相关的代码都挪到JAVA中去吧。

8.1.3 监视器等待和唤醒

JAVA还提供了其它一些和线程监视器有关的API:Object.wait、Object.notify、Object.notifyAll。因为监视器等待和唤醒操作没有进入和退出操作对时效性要求那么高,所以,没有提供与这些方法相对应的JNI函数。我们可以通过JNI调用JAVA的机制来调用这些方法。

/* precomputed method IDs */

static jmethodID MID_Object_wait;

static jmethodID MID_Object_notify;

static jmethodID MID_Object_notifyAll;

void   JNU_MonitorWait(JNIEnv *env, jobject object, jlong timeout)

{

(*env)->CallVoidMethod(env, object, MID_Object_wait    timeout);

}

void  JNU_MonitorNotify(JNIEnv *env, jobject object)

{

(*env)->CallVoidMethod(env, object, MID_Object_notify);

}

void JNU_MonitorNotifyAll(JNIEnv *env, jobject object)

{

(*env)->CallVoidMethod(env, object, MID_Object_notifyAll);

}

上例中,我们假设Object.wait、Object.notify和Object.notifyAll已经在其它地方计算好并缓存在全局引用里面了。

8.1.4 在任意地方获取JNIEnv指针

前面我们提到了,JNIEnv指针只在当前线程中有效。那么有没有办法可以从本地代码的任意地方获取到JNIEnv指针呢?比如,一个操作系统的回调函数中,本地代码是无法通过传参的方式获取到JNIEnv指针的。

可以通过调用接口(invocation interface)中的AttachCurrentThread方法来获取到当前线程中的JNIEnv指针:

JavaVM *jvm; /* already set */

f()

{

JNIEnv *env;

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

... /* use env */

}

一旦当前线程被附加到JVM上,AttachCurrentThread函数就会返回一个属于当前线程的JNIEnv指针。有许多方式可以获取JavaVM指针。可以在VM创建的时候记录下来,也可以通过JNI_GetCreatedJavaVMs查询被创建的虚拟机,还可以通过调用JNI函数GetJavaVM或者定义JNI_OnLoad句柄接口。与JNIEnv不同的是,JavaVM只要被缓存在全局引用中,是可以被跨线程使用的。

JDK1.2以后提供了一个新调用接口(invocation interface)函数GetEnv,这样,你就可以检查当前线程是否被附加到JVM上,然后返回属于当前线程的JNIEnv指针。如果当前线程已经被附加到VM上的话,GetEnv和AttachCurrentThread在功能上是等价的。

jni和线程的更多相关文章

  1. JNI通过线程c回调java层的函数

    1.参看博客:http://www.jianshu.com/p/e576c7e1c403 Android JNI 篇 - JNI回调的三种方法(精华篇) 2.参看博客: JNI层线程回调Java函数关 ...

  2. 解决JNI native 线程不能正常退出的问题

    本人刚涉足学习C++ 安卓  java,遇到这个棘手的问题,多谢博客园作者lknlfy 看了你的博客解决了这个问题,此文转发, 方便日后学习 以下内容转自lknlfy作者博客  传送门:http:// ...

  3. 【胡思乱想】JNI与线程池的维护

    JNI中,C/C++代码里创建的资源不由Java GC处理,故这里的资源必须由C/C++代码明确释放.在JNI中,C/C++回调Java的方法是调用一个CallXXMethod函数来实现的,如果回调的 ...

  4. 解决安卓JNI native 线程不能正常退出问题二

    直面这个解决方法的可以看我转载的博客            https://www.cnblogs.com/Carlsblog/p/9438016.html 本方法是个投机取巧法,不过也解决了不能正常 ...

  5. Android JNI 启动线程,并设置线程名称

    p.p1 { margin: 0; font: 12px Menlo; color: rgba(100, 56, 32, 1); background-color: rgba(255, 255, 25 ...

  6. jni调试3(线程调试env变量问题)

    jni层调试线程死机原因 一,导致死机原因:   jni层中  线程函数中  只要添加调用env 的函数 ,,就会死机     二,解决方法 第一我们应该理解: ①(独立性) JNIEnv 是一个与线 ...

  7. JNI与多线程

    在android开发过程中,由于主线程要聚焦于UI交互,为了软件运行流畅必然要用到很多多线程技术.而在JNI机制中专门提供了一些避免线程冲突的函数.了解.学习并掌握如何避免线程冲突问题是一个程序猿的必 ...

  8. Java层与Jni层的数组传递(转)

    源:Java层与Jni层的数组传递 Android开发中,经常会在Java代码与Jni层之间传递数组(byte[]),一个典型的应用是Java层把需要发送给客户端的数据流传递到Jni层,由Jni层的S ...

  9. JNI详解---从不懂到理解

    转载:https://blog.csdn.net/hui12581/article/details/44832651 Chap1:JNI完全手册... 3 Chap2:JNI-百度百科... 11 C ...

随机推荐

  1. django cms 5月第一弹

    官方文档: ##http://django-cms.readthedocs.io/en/latest/index.html #截图 #生存的项目结构

  2. Bootstrap自带的那些常用插件

    1.Bootstrap自带的那些常用插件. 1.1模态框 模态框的HTML代码放置的位置 务必将模态框的HTML代码放在文档的最高层级内(也就是说,尽量作为 body 标签的直接子元素),以避免其他组 ...

  3. H5 + WebGL 展示的3D无人机

    前言 近年来,无人机的发展越发迅速,既可民用于航拍,又可军用于侦察,涉及行业广泛,也被称为“会飞的照相机”.但作为军事使用,无人机的各项性能要求更加严格.重要.本系统则是通过 Hightopo 的   ...

  4. 超链接a标签的伪类选择器问题,Link标签与visited标签的失效问题(问题介绍与解决方法)。

    <!DOCTYPE html>< html>< head>     <meta charset="utf-8" />     < ...

  5. 目标检测——深度学习下的小目标检测(检测难的原因和Tricks)

    小目标难检测原因 主要原因 (1)小目标在原图中尺寸比较小,通用目标检测模型中,一般的基础骨干神经网络(VGG系列和Resnet系列)都有几次下采样处理,导致小目标在特征图的尺寸基本上只有个位数的像素 ...

  6. Java并发编程(一):线程基础知识以及synchronized关键字

    1.线程与多线程的概念:在一个程序中,能够独立运行的程序片段叫作“线程”(Thread).多线程(multithreading)是指从软件或者硬件上实现多个线程并发执行的技术. 2.多线程的意义:多线 ...

  7. Codeforces_807

    A. 严格按照题目给的两个条件来. #include<bits/stdc++.h> using namespace std; ],b[]; int main() { ios::sync_w ...

  8. 2019牛客多校2 F Partition problem(dfs)

    题意: n<=28个人,分成人数相同的两组,给你2*n*2*n的矩阵,如果(i,j)在不同的组里,竞争力增加v[i][j],问你怎么分配竞争力最 4s 思路: 枚举C(28,14)的状态,更新答 ...

  9. 《Python学习手册 第五版》 -第8章 列表与字典

    前面已经讲过数值类型(第5章)和字符串类型(第7章),本章继续其他数据类型的讲解:列表和字典 本章的核心内容 1.列表 1)什么是列表 2)基本列表操作 3)列表迭代和推导 4)索引.分片和矩阵 5) ...

  10. EMC networker nmm can restore and recover sqlserver as different name to different location

    EMC networker nmm can restore and recover sqlserver as different name to different location That is ...