要在jni代码的线程中调用java代码的方法,必须把当前线程连接到VM中,获取到一个[JNIEnv*].

A JNI interface pointer (JNIEnv*) is passed as an argument for each native function mapped to a Java method, allowing for interaction with the JNI environment within the native method.This JNI interface pointer can be stored, but remains valid only in the current thread. Other threads must first call AttachCurrentThread()to attach themselves to the VM and obtain a JNI interface pointer. Once attached, a native thread works like a regular Java thread running within a native method. The native thread remains attached to the VM until it callsDetachCurrentThread() to detach itself.[3]
JNI接口指针(JNIEnv*)作为映射到Java方法的每个本地函数的参数传递,允许与本机方法内的JNI环境进行交互。可以存储此JNI接口指针,但仅在当前线程中保持有效。其他线程必须首先调用AttachCurrentThread()将自己连接到VM并获取JNI接口指针。连接后,本机线程的工作方式类似于在本机方法中运行的常规Java线程。本机线程将保持连接到VM,直到它调用DeachCurrentThread()以分离自身。[3]

即:当在一个线程里面调用AttachCurrentThread后,如果不需要用的时候一定要DetachCurrentThread,否则线程无法正常退出。
注意点
1 保存全局 JavaVM
2 保存全局 jobject
3 退出线程必须调用 DetachCurrentThread

相关函数
【GetEnv】
返回结果为 JNI_OK 表示当前线程已经绑定到 VM 中 ,如果未绑定再调用 AttachCurrentThread
【NewStringUTF】
该方法可以不调用 DeleteLocalRef, openJdk中的例程使用也不需要释放,不过释放相对较好

#include "jni_main.h"
#include <pthread.h>
#include <stdio.h>static const char* ClassPathName = "com/example/hellojni/JniClass";static JavaVM *ms2_vm = NULL;
static jobject g_obj;static JNINativeMethod JnidecgMethods[] = {{"jni_debug_test1","()V",(void *) jni_debug_test1},
};bool get_env(JNIEnv ** env) {int status = ms2_vm->GetEnv((void**) env, JNI_VERSION_1_4);if (status != JNI_OK) {status = ms2_vm->AttachCurrentThread(env, NULL);if(status != JNI_OK){ehome_printf("[%s]FAILED\n", __FUNCTION__);return false;}ehome_printf("[%s]SUCCESS\n", __FUNCTION__);}else{ehome_printf("[%s]Attach aready\n", __FUNCTION__);}return true;
}void release_env(void) {JNIEnv *env ;int status = ms2_vm->GetEnv((void**)&env, JNI_VERSION_1_4);if (status == JNI_OK) {ehome_printf("[%s]getpid=%d, gettid=%d\n", __FUNCTION__, getpid(),gettid());ms2_vm->DetachCurrentThread();}else{ehome_printf("[%s]NEED NOT DETACH\n", __FUNCTION__);}
}jint JNI_OnLoad(JavaVM* vm, void* reserved) {JNIEnv* env = NULL;if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {return -1;}jclass clazz = env->FindClass(ClassPathName);if (clazz == NULL) {ehome_printf("[%s]cannot find class '%s'\n", __FUNCTION__,ClassPathName);return -1;}if (env->RegisterNatives(clazz, JnidecgMethods,sizeof(JnidecgMethods) / sizeof(JnidecgMethods[0])) < 0) {ehome_printf("[%s]failed for '%s'\n", __FUNCTION__,ClassPathName);return (-1);}ms2_vm = vm;return JNI_VERSION_1_4;
}static void* thread_debug1(void* argv){JNIEnv *env ;if (!get_env(&env)) {ehome_printf("[%s]get_env error!\n", __FUNCTION__);return NULL;}ehome_printf("[%s]GetVersion=%d\n", __FUNCTION__, env->GetVersion());jclass clazz = env->GetObjectClass(g_obj);if (clazz == NULL) {ehome_printf("[%s]unable to find class '%s'\n", __FUNCTION__, ClassPathName);release_env();return NULL;}jmethodID CallBackid = env->GetMethodID(clazz, "on_post_from_jni","(I)V");for(int i=0; i<5; i++){env->CallVoidMethod(g_obj, CallBackid, 1001+i);sleep(1);}release_env();return NULL;
}static void* thread_debug2(void* argv){JNIEnv *env ;if (!get_env(&env)) {ehome_printf("[%s]get_env error!\n", __FUNCTION__);return NULL;}ehome_printf("[%s]GetVersion=%d\n", __FUNCTION__, env->GetVersion());jclass clazz = env->GetObjectClass(g_obj);if (clazz == NULL) {ehome_printf("[%s]unable to find class '%s'\n", __FUNCTION__, ClassPathName);release_env();return NULL;}jmethodID CallBackid = env->GetMethodID(clazz, "on_post_from_jni","(I)V");for(int i=0; i<5; i++){env->CallVoidMethod(g_obj, CallBackid, 2001+i);get_env(&env);sleep(1);}release_env();return NULL;
}static void* thread_debug3(void* argv){JNIEnv *env ;if (!get_env(&env)) {ehome_printf("[%s]get_env error!\n", __FUNCTION__);return NULL;}ehome_printf("[%s]GetVersion=%d\n", __FUNCTION__, env->GetVersion());//jclass clazz = env->GetObjectClass(g_obj);jclass clazz = env->FindClass("android/util/Log");if (clazz == NULL) {ehome_printf("[%s]unable to find class '%s'\n", __FUNCTION__, ClassPathName);release_env();return NULL;}jmethodID CallBackid = env->GetStaticMethodID(clazz, "w","(Ljava/lang/String;Ljava/lang/String;)I");jstring jstr1;jstring jstr2;char text[32] = {0};for(int i=0; i<5; i++){sprintf(text, "%s.%d", __FUNCTION__, i);jstr1 = env->NewStringUTF("JNI_TAG");jstr2 = env->NewStringUTF(text);env->CallStaticIntMethod(clazz, CallBackid, jstr1, jstr2);env->DeleteLocalRef(jstr1);env->DeleteLocalRef(jstr2);sleep(1);}release_env();return NULL;
}JNIEXPORT void JNICALL jni_debug_test1(JNIEnv *jenv, jobject thiz){ehome_printf("[%s]start\n", __FUNCTION__);g_obj = jenv->NewGlobalRef(thiz);pthread_t tid1;pthread_create(&tid1, NULL, thread_debug1, NULL);pthread_t tid2;pthread_create(&tid2, NULL, thread_debug2, NULL);pthread_t tid3;pthread_create(&tid3, NULL, thread_debug3, NULL);
}

头文件 jni_main.h

#ifndef _JNI_MAIN_H_
#define _JNI_MAIN_H_
#include <jni.h>
#include <android/log.h>
#include <unistd.h>#define ehome_printf(format, ...)  \__android_log_print(ANDROID_LOG_DEBUG,  "jni_debug", format, ##__VA_ARGS__)#ifdef __cplusplus
extern "C"
{
#endifJNIEXPORT void JNICALL jni_debug_test1(JNIEnv *jenv, jobject thiz);#ifdef __cplusplus
}
#endif#endif

运行结果

01-01 01:25:11.925: D/jni_debug(11967): [jni_debug_test1]start
01-01 01:25:11.929: D/jni_debug(11967): [get_env]SUCCESS
01-01 01:25:11.929: D/jni_debug(11967): [thread_debug2]GetVersion=65542
01-01 01:25:11.929: I/JniClass(11967): on_post_from_jni: number=2001
01-01 01:25:11.929: D/jni_debug(11967): [get_env]Attach aready
01-01 01:25:11.934: D/jni_debug(11967): [get_env]SUCCESS
01-01 01:25:11.934: D/jni_debug(11967): [thread_debug1]GetVersion=65542
01-01 01:25:11.934: I/JniClass(11967): on_post_from_jni: number=1001
01-01 01:25:11.938: D/jni_debug(11967): [get_env]SUCCESS
01-01 01:25:11.938: D/jni_debug(11967): [thread_debug3]GetVersion=65542
01-01 01:25:11.938: W/JNI_TAG(11967): thread_debug3.0
01-01 01:25:12.929: I/JniClass(11967): on_post_from_jni: number=2002
01-01 01:25:12.929: D/jni_debug(11967): [get_env]Attach aready
01-01 01:25:12.934: I/JniClass(11967): on_post_from_jni: number=1002
01-01 01:25:12.939: W/JNI_TAG(11967): thread_debug3.1
01-01 01:25:13.929: I/JniClass(11967): on_post_from_jni: number=2003
01-01 01:25:13.930: D/jni_debug(11967): [get_env]Attach aready
01-01 01:25:13.934: I/JniClass(11967): on_post_from_jni: number=1003
01-01 01:25:13.939: W/JNI_TAG(11967): thread_debug3.2
01-01 01:25:14.930: I/JniClass(11967): on_post_from_jni: number=2004
01-01 01:25:14.930: D/jni_debug(11967): [get_env]Attach aready
01-01 01:25:14.935: I/JniClass(11967): on_post_from_jni: number=1004
01-01 01:25:14.939: W/JNI_TAG(11967): thread_debug3.3
01-01 01:25:15.930: I/JniClass(11967): on_post_from_jni: number=2005
01-01 01:25:15.930: D/jni_debug(11967): [get_env]Attach aready
01-01 01:25:15.935: I/JniClass(11967): on_post_from_jni: number=1005
01-01 01:25:15.940: W/JNI_TAG(11967): thread_debug3.4
01-01 01:25:16.930: D/jni_debug(11967): [release_env]getpid=11967, gettid=11999
01-01 01:25:16.935: D/jni_debug(11967): [release_env]getpid=11967, gettid=11997
01-01 01:25:16.940: D/jni_debug(11967): [release_env]getpid=11967, gettid=12000

线程中使用AttachCurrentThread得到JNIEnv相关推荐

  1. Android-JNI开发系列《二》-在jni层的线程中回调到java层

    人间观察 忽有故人心上头,回首山河已是秋. 马上国庆+中秋了--- 今天我们看一个比较常见的场景: 当我们处理一个密集型计算数据(比如音视频的软编解码处理,bitmap的特效处理等),这时候就需要用c ...

  2. java线程的异常无法捕获异常_Java如何从线程中捕获异常

    我有Java主类,在该类中,我启动了一个新线程,在主类中,它等待线程死亡.在某个时刻,我从线程中抛出了运行时异常,但是我无法在主类中捕获从线程中抛出的异常. 这是代码: public class Te ...

  3. DllMain中不当操作导致死锁问题的分析——线程中调用GetModuleFileName、GetModuleHandle等导致死锁

    之前的几篇文章已经讲解了在DllMain中创建并等待线程导致的死锁的原因.是否还记得,我们分析了半天汇编才知道在线程中的死锁位置.如果对于缺乏调试经验的同学来说,可能发现这个位置有点麻烦.那么本文就介 ...

  4. 获取线程中抛出的异常信息

    1 ScheduledExecutorService service = Executors.newScheduledThreadPool(10); 2 // 从现在开始delay毫秒之后,每隔一天执 ...

  5. python3线程中的锁机制

    1.锁的形象解释 有一个奇葩的房东,他家里有两个房间想要出租.这个房东很抠门,家里有两个房间,但却只有一把锁,不想另外花钱是去买另一把锁,也不让租客自己花钱加锁.这样租客只有先租到的那个人才能分配到锁 ...

  6. python如何次传参给线程_python如何给线程中的函数传参?

    1.Process说明 (1)概念 process模块是一个创建进程的模块,借助这个模块,就可以完成进程的创建. (2)语法([group [, target [, name [, args [, k ...

  7. 用Handler的post()方法来传递线程中的代码段到主线程中执行

    自定义的线程中是不能更新UI的,但是如果遇到更新UI的事情,我们可以用handler的post()方法来将更新UI的方法体,直接传送到主线程中,这样就能直接更新UI了.Handler的post()方法 ...

  8. 一个线程中lock用法的经典实例

    1 /* 2 该实例是一个线程中lock用法的经典实例,使得到的balance不会为负数 3 同时初始化十个线程,启动十个,但由于加锁,能够启动调用WithDraw方法的可能只能是其中几个 4 作者: ...

  9. 【Based Android】Android Sensor感应器介绍(二)线程中刷新UI 创建一个android测力计...

    上一篇文章http://www.cnblogs.com/octobershiner/archive/2011/11/06/2237880.html介绍了sensor的基本知识以及一个使用其中加速度感应 ...

最新文章

  1. 两个月番茄组长的收获总结
  2. (C++)1009 Product of Polynomials
  3. wince: Post-deploy error 0x00000001 returned after calling......解决方法
  4. PyObject_CallMethod
  5. Signalr实时通讯
  6. go的各种import
  7. Eclipse中Build Path的使用介绍---学习笔记
  8. 流水线调度(51Nod-1205)
  9. CentOS7 ISCSI服务器搭建
  10. 内网嗅探自我保护用到的批处理
  11. 新年到!充满年味的海报给你参考
  12. tfs 解除锁定命令
  13. node.js 安装详细步骤教程
  14. IDEA打包jar包并运行
  15. php 微信登录手机网站,微信PC端登录和手机端登录逻辑分享
  16. GPU编程3--GPU内存深入了解
  17. 博士申请 | 加拿大麦克马斯特大学郑榕教授招收全奖博士生/博士后
  18. table表格表头单元格添加斜线
  19. Spring Cloud 2.2.2 源码之二十九nacos客户端获取配置原理四
  20. 运维PaaS平台,让数据发挥更大的价值

热门文章

  1. Tomcat配置、创建Web项目
  2. 请举例说明俄语句子里的主语补足语和宾语补足语,及区别
  3. cut最后几位 shell_详解Shell cut用法
  4. sa登录时的各种错误
  5. html怎么看兼不兼容浏览器,六大双核浏览器HTML5兼容性测试
  6. matlab绕线式三级串阻,三相绕线式异步电动机转子串电阻起动的MATLAB仿真.docx
  7. 《学习笔记》------温故而知新
  8. android 5.0儿童模式,三星Galaxy S5如何进入儿童模式
  9. linux中管道符号打不出来,linux 管道符号 | ,以及 ||等等特殊符号笔记
  10. 12升24V10A大电流升压同步整流方案