JNI 多线程
一、概述
JNI编程和Linux上的C/C++编程还是挺相似的,每次java调用JNI中的函数时都会传入有关JVM的一些参数(如JNIEnv,jobject),每次JNI回调java中的方法时都要通过JVM的有关参数来实现,当在JNI中涉及到多线程的话还是有一些不一样的地方,就是要在子线程函数里使用AttachCurrentThread()和DetachCurrentThread()这两个函数,在这两个函数之间加入回调java方法所需要的代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<pthread.h> #include<jni.h> #include<android/log.h> #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "native-activity", __VA_ARGS__)) #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "native-activity", __VA_ARGS__)) #define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "native-activity", __VA_ARGS__)) //线程数 #define NUMTHREADS 5 //全局变量 JavaVM *g_jvm = NULL; jobject g_obj = NULL; void *thread_fun( void * arg) { JNIEnv *env; jclass cls; jmethodID mid; //Attach主线程 if ((*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL) != JNI_OK) { LOGE( "%s: AttachCurrentThread() failed" , __FUNCTION__); return NULL; } //找到对应的类 cls = (*env)->GetObjectClass(env,g_obj); if (cls == NULL) { LOGE( "FindClass() Error....." ); goto error; } //再获得类中的方法 mid = (*env)->GetStaticMethodID(env, cls, "fromJNI" , "(I)V" ); if (mid == NULL) { LOGE( "GetMethodID() Error....." ); goto error; } //最后调用java中的静态方法 (*env)->CallStaticVoidMethod(env, cls, mid ,( int )arg); error: //Detach主线程 if ((*g_jvm)->DetachCurrentThread(g_jvm) != JNI_OK) { LOGE( "%s: DetachCurrentThread() failed" , __FUNCTION__); } pthread_exit(0); } //由java调用以创建子线程 JNIEXPORT void Java_com_nan_thread_MyThreadActivity_mainThread( JNIEnv* env, jobject obj) { int i; pthread_t pt[NUMTHREADS]; for (i = 0; i < NUMTHREADS; i++) //创建子线程 pthread_create(&pt[i], NULL, &thread_fun, ( void *)i); } //由java调用来建立JNI环境 JNIEXPORT void Java_com_nan_thread_MyThreadActivity_setJNIEnv( JNIEnv* env, jobject obj) { //保存全局JVM以便在子线程中使用 (*env)->GetJavaVM(env,&g_jvm); //不能直接赋值(g_obj = obj) g_obj = (*env)->NewGlobalRef(env,obj); } //当动态库被加载时这个函数被系统调用 JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { JNIEnv* env = NULL; jint result = -1; //获取JNI版本 if ((*vm)->GetEnv(vm, ( void **)&env, JNI_VERSION_1_4) != JNI_OK) { LOGE( "GetEnv failed!" ); return result; } return JNI_VERSION_1_4; } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南