线程中使用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,否则线程无法正常退出。

#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);
}

运行结果

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

上一篇:JNI RegisterNatives注册原生方法


下一篇:Jni 线程JNIEnv,JavaVM,JNI_OnLoad(GetEnv返回NULL?FindClass返回NULL?)