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

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

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. .NET 云原生架构师训练营(模块二 基础巩固 引入)--学习笔记

    2.1 引入 http协议 web server && web application framework .net 与 .net core asp .net core web api ...

  2. Kafka-基本介绍和常见问题

    1.kafka 1.1.kafka介绍 ​ kafka是最初由linkedin公司开发的,使用scala语言编写,kafka是一个分布式,分区的,多副本的,多订阅者的消息队列系统. 1.2.kafka ...

  3. [Ngbatis源码学习][SpringBoot] 由BeanFactoryPostProcessor想到

    由BeanFactoryPostProcessor想到 在看Ngbatis源码时看到了对BeanFactoryPostProcessor后置处理器的使用,对其的使用并不是很了解,在此做一些学习和总结. ...

  4. 借助Rich库实现Pandas DataFrame颜值升级

    pandas的DataFrame功能强大自不必说,它可以帮助我们极大的提高统计分析的效率. 不过,使用DataFrame开发我们的分析程序的时候,经常需要打印出DataFrame的内容,以验证和调试数 ...

  5. HASHTEAM香山杯2023WP

    目录 前言 misc 签到题 web PHP_unserialize_pro Re URL从哪儿来 hello python pwn Move pwthon 附上c-python调试方法 crypto ...

  6. Centos8 安装 Redis6.0.16

    下载,解压,编译,安装 安装至 /opt/redis/redis-6.0.16 目录 tar xvf redis-6.0.16.tar.gz gcc --version cd redis-6.0.16 ...

  7. Vim常用快捷键汇总

    跳到指定行 在命令行模式下输入: :n(n为指定行号)

  8. Hi3516开发笔记(八):Hi3516虚拟机交叉开发环境搭建之配置QtCreator开发交叉编译环境

    海思开发专栏 上一篇:<Hi3516开发笔记(七):Hi3516虚拟机交叉开发环境搭建之交叉编译Qt>下一篇:<Hi3516开发笔记(九):在QtCreator开发环境中引入海思sd ...

  9. day07---系统命令

    课程知识概述--系统命令 seq cat less more head tail grep tr alias 复习 1.echo -e 激活特殊的意义 \n 表示回车 \t tab键 [root@ol ...

  10. 第134篇:解决浏览器的CORS跨域问题(CORS policy: Cross origin requests are only supported for protocol schemes: http, data, isolated-app, chrome-extension, chrome-untrusted, https, edge.)

    好家伙,   我继续尝试着将我的飞机大战使用ES6模块化分离开来,出了点问题 1.出现问题: edge,chrome等一系列浏览器,会为了安全,禁止你跨域访问 目录如下: 主程序  index.htm ...