在《Java与CC++交互JNI编程》中有讲过AttachCurrentThreadDetachCurrentThread的使用。

我们知道在jni中我们可以使用pthread或者std::thread创建线程。因为线程并不是从Java环境创建的,所以这时候创建出的线程是没有JNIEnv的。如果需要使用JNIEnv,可以调用JavaVMAttachCurrentThread将当前线程附加到虚拟机。

jint AttachCurrentThread(JNIEnv** p_env, void* thr_args);

AttachCurrentThread可以调用多次,第一次会附加当前线程到虚拟机并返回JNIEnv,之后再调用的时候因为当前线程已经被附加到虚拟机上了,所以就不需要重复附加了,仅仅只返回JNIEnv即可,作用相当于GetEnv

需要注意的是,在线程退出之前我们必须要调用DetachCurrentThread从虚拟机分离当前线程,,不然会造成内存泄露,线程也不会退出。对于native层创建出来的线程,在调用AttachCurrentThread的时候会创建本地引用表,在调用DetachCurrentThread的时候会释放本地引用表。

但是一般我们并不会频繁的调用AttachCurrentThread/DetachCurrentThread,这样效率很低。一般我们在线程的入口函数调用一次AttachCurrentThread,在线程入口函数退出之前调用一次DetachCurrentThread即可。所以一定要手动释放每个本地引用。不然本地引用越来越多,很容易超出最大限制。

下面这个例子很好的演示了AttachCurrentThread/DetachCurrentThread的用法:

#include <jni.h>
#include <pthread.h>
#include <android/log.h> extern JavaVM *g_vm;
JNIEnv* getEnv(); void* __start_routine(void*) {
JNIEnv *env1, *env2, *env3, *env4, *env5;
int ret; JavaVMAttachArgs args;
args.version = JNI_VERSION_1_4;
args.name = "pthread-test";//给线程起个名字吧,这样在调试或者崩溃的时候能显示出名字,而不是thead-1,thread-2这样的名字。
args.group = NULL;//java.lang.ThreadGroup的全局引用,作用你懂的。 //在调用AttachCurrentThread以前,是没有java环境的,所以GetEnv返回的JNIEnv是NULL
g_vm->GetEnv((void**)&env1,JNI_VERSION_1_4);
__android_log_print(ANDROID_LOG_DEBUG, "MD_DEBUG", "before AttachCurrentThread env is:%p", env1); //调用AttachCurrentThread,将当前线程附加到虚拟机,附加成功后,将会返回JNIEnv
ret = g_vm->AttachCurrentThread(&env2, &args);
__android_log_print(ANDROID_LOG_DEBUG, "MD_DEBUG", "do AttachCurrentThread env is:%p, ret=%d", env2, ret); //在调用AttachCurrentThread以后,GetEnv返回了正确的JNIEnv
g_vm->GetEnv((void**)&env3,JNI_VERSION_1_4);
__android_log_print(ANDROID_LOG_DEBUG, "MD_DEBUG", "after AttachCurrentThread env is:%p", env3); //再次调用AttachCurrentThread,直接返回JNIEnv,作用相当于GetEnv
ret = g_vm->AttachCurrentThread(&env4, NULL);
__android_log_print(ANDROID_LOG_DEBUG, "MD_DEBUG", "retry AttachCurrentThread env is:%p, ret=%d", env4, ret); //从虚拟机分离线程
g_vm->DetachCurrentThread(); //在调用DetachCurrentThread以后,GetEnv返回NULL
g_vm->GetEnv((void**)&env5,JNI_VERSION_1_4);
__android_log_print(ANDROID_LOG_DEBUG, "MD_DEBUG", "after DetachCurrentThread env is:%p", env5);
return NULL;
} extern "C" JNIEXPORT void Java_com_example_threadtest_PThread_start(JNIEnv *env, jclass clazz) {
pthread_t thread;
pthread_create(&thread, NULL, __start_routine, NULL);
}

深入浅出Android NDK之在jni中使用线程

关于JNI开发的一些建议

JNI中AttachCurrentThread和DetachCurrentThread的问题的更多相关文章

  1. ZT ANDROID jni 中的事件回调机制JNIenv的使用 2012-09-10 12:53:01

    ANDROID jni 中的事件回调机制JNIenv的使用 2012-09-10 12:53:01 分类: 嵌入式 android framework 里java调用native,使用JNI机制,ja ...

  2. Java Native Interface 六JNI中的异常

    本文是<The Java Native Interface Programmer's Guide and Specification>读书笔记 在这里只讨论调用JNI方法可能会出现的异常, ...

  3. Java Native Interfce三在JNI中使用Java类的普通方法与变量

    本文是<The Java Native Interface Programmer's Guide and Specification>读书笔记 前面我们学习了如何在JNI中通过参数来使用J ...

  4. Java Native Interface 二 JNI中对Java基本类型和引用类型的处理

    本文是<The Java Native Interface Programmer's Guide and Specification>读书笔记 Java编程里会使用到两种类型:基本类型(如 ...

  5. JNI中C调用Java方法

    背景需求 我们需要在JNI的C代码调用Java代码.实现原理:使用JNI提供的反射借口来反射得到Java方法,进行调用. JNI关键方法讲解. 1. 在同一个类中,调用其他方法 JNIEXPORT v ...

  6. [Android Pro] Android studio jni中调用Log输出调试信息

    reference to : http://www.linuxidc.com/Linux/2014-02/96341.htm Android 开发中,java 可以方便的使用调试信息Log.i, Lo ...

  7. Jni中C++和Java的参数传递 参数对照

    Jni中C++和Java的参数传递 如何使用JNI的一些基本方法和过程在网上多如牛毛,如果你对Jni不甚了解,不知道Jni是做什么的,如何建立一个基本的jni程序,或许可以参考下面下面这些文章:利用V ...

  8. Jni中C++和Java的参数传递

    Jni中C++和Java的参数传递 如何使用JNI的一些基本方法和过程在网上多如牛毛,如果你对Jni不甚了解,不知道Jni是做什么的,如何建立一个基本的jni程序,或许可以参考下面下面这些文章:利用V ...

  9. Base64编解码Android和ios的例子,补充JNI中的例子

    1.在Android中java层提供了工具类:android.util.Base64; 里面都是静态方法,方便直接使用: 使用方法如下: // Base64 编码: byte [] encode =  ...

  10. android学习笔记----JNI中的c控制java

    面向对象的底层实现 java作为面向对象高级语言,可对现实世界进行建模.和面向过程不同的是面向对象软件的编写不是流程的堆积,而是对业务逻辑的多视角分解和分类.其过程大致为:      1).将知识分解 ...

随机推荐

  1. setjmp/longjmp使用问题

    setjmp/longjmp开启编译优化后导致出现无法正常使用

  2. 聚石塔的K8s 容器服务使用注意事项,坑的总结

    1. 首先聚石塔是不能使用 8080 端口的,会审核不通过. 2.然而,容器服务默认的却是8080,最彻底的解决方法就是修改成80,注意3个地方: 以上3个地方要严重留意,缺一不可,已经踩了2次坑了, ...

  3. npm i -D和-s及-g以及--save的那些事

      i 是 install 的简写 -S 就是 --save 的简写 -D 就是 --save-dev 的简写 npm i module_name -S = > npm install modu ...

  4. Linux通过fdisk或者parted进行磁盘分区,然后格式化和挂载磁盘

    磁盘分区是Linux的常用命令,其中fdisk和parted命令最为常用.但是当磁盘大于2T时,fdisk只能分到2T. 比如4T的磁盘,fdisk只能分2T的主分区出来,parted可以直接分成4T ...

  5. DecisionTreeClassifier&DecisionTreeClassRegression

    DecisionTreeClassifier from sklearn.datasets import load_wine # 红酒数据集 from sklearn.tree import Decis ...

  6. NC19782 Tree

    题目链接 题目 题目描述 修修去年种下了一棵树,现在它已经有n个结点了. 修修非常擅长数数,他很快就数出了包含每个点的连通点集的数量. 澜澜也想知道答案,但他不会数数,于是他把问题交给了你. 输入描述 ...

  7. NC17872 CSL的校园卡

    题目链接 题目 题目描述 今天是阳光明媚,晴空万里的一天,CSL早早就高兴地起床走出寝室到校园里转悠. 但是,等到他回来的时候,发现他的校园卡不见了,于是他需要走遍校园寻找它的校园卡.CSL想要尽快地 ...

  8. SSD 表项管理概述(一)——L1、L2、L3

    分类 名称 说明 映射表相关 L1 Table 记录每个4KB用户数据在SSD上的存放物理地址: L2 Table 记录每个sub L1 Table在SSD上的存放物理地址: L3 Table 记录每 ...

  9. C++ 多线程的错误和如何避免(8)

    不要重复获取同一个锁 问题:在获得一个锁并且没有释放该锁的前提下,再次尝试获取该锁会报错. 比如, #include <iostream> #include <thread> ...

  10. win32-localtime的使用

    下面的例子用于反映本地系统的日期格式变化 // locale test #include <stdio.h> #include <locale.h> #include < ...