线程中使用AttachCurrentThread得到JNIEnv

要在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"
{
#endif

JNIEXPORT 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

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值