在《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. opcache导致的RCE复现

    前言 RCE得搭配着文件上传的点来进行利用 环境搭建 用docker搭个php7的环境,作者用的php7.0 docker run -itd --name php7 -p 8083:80 php:7. ...

  2. (C语言)每日代码||2023.12.27||关于(++i)+(++i)以及(++i)+(i = 100)

    #include <stdio.h> int main() { int i = 1; int a = (++i) + (++i); printf("a = %d,i = %d\n ...

  3. 零基础入门Vue之影分身之术——列表渲染&渲染原理浅析

    听我说 从 条件渲染 那一篇,我学习到了如何用Vue对dom节点根据条件显示 但单单有条件还不够啊,有时候数据是一大坨一大坨的数据,如果Vue不提供咱要么使用"v-html" 要么 ...

  4. 17.5 稀疏调拨的内存映射文件--《Windows核心编程》

    原文链接:https://www.likecs.com/show-306421749.html,原文中代码是C++MFC程序,更详细.本文是C语言测试代码. (1)稀疏文件(Sparse File)定 ...

  5. 用ELK分析每天4亿多条腾讯云MySQL审计日志(3)--下载日志

    当初分析日志,麻烦的是腾讯云的SQL审计日志下载,有下列限制: 1,单次最多1000万条下载 2,单个实例最多生成5条日志文件,多的要先删除以前文件才能生成   腾讯云日志文件生成界面:      一 ...

  6. Eclipse搭建Struts2项目

    最近在系统性的学习maven,碰到搭建struts2环境,特此记录一下. 1.创建maven工程 2.添加依赖 pom.xml文件内容如下 <project xmlns="http:/ ...

  7. SpringBoot下Akka的简单使用

    SpringBoot下Akka的简单使用 Akka框架实现一个异步消息传输,通过定义演员来处理业务逻辑. 首先引入依赖 <!-- akka --> <dependency> & ...

  8. 我的小程序之旅二:如何创建一个微信小程序

    第一步.准备邮箱 如果只是个人想体验一下小程序,直接用自己的QQ邮箱就行,但是这样申请的小程序很多权限都是没有的,比如获取用户手机号授权. 如果是企业或服务商要进行开发小程序,那么至少准备三个邮箱,同 ...

  9. std::shared_ptr 线程安全方面的思考

    一直惦记着 std::shared_ptr 线程安全的问题,看了些文章后,又怕过段时间忘记了,遂记录下来 std::shared_ptr 的线程安全问题主要有以下两种: 引用计数的加减操作是否线程安全 ...

  10. 【Android逆向】定位native函数在哪个so中方法

    1. 在逆向过程中经常需要定位方法在哪个so中,而app加载的so很多,比如 那么如何快速定位方法在哪里呢 2. 比如如下案例,首先看日志 03-28 11:01:56.457 14566 14566 ...