news 2026/5/1 5:03:25

JNI 编程指南12—— JNI多线程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JNI 编程指南12—— JNI多线程

目录

  • 核心要点
  • 示例程序

JNI多线程

核心要点

JNI 环境下,进行多线程编程,有以下两点是需明确的:

  • JNIEnv 是一个线程作用域的变量,不能跨线程传递,每个线程都有自己的 JNIEnv 且彼此独立
  • 局部引用不能在本地函数中跨函数使用,不能跨线程使用,当然也不能直接缓存起来使用

示例程序

示例程序主要演示:

如何在子线程获取到属于子线程自己的 JNIEnv
上面说了局部引用不能再线程之间直接传递,所以我们只有另觅他法
Java 层:

publicvoidjavaCallback(intcount){Log.e(TAG,"onNativeCallBack : "+count);}publicnativevoidthreadTest();

Native 层:

staticintcount=0;JavaVM*gJavaVM=NULL;//全局 JavaVM 变量jobject gJavaObj=NULL;//全局 Jobject 变量jmethodID nativeCallback=NULL;//全局的方法ID//这里通过标志位来确定 两个线程的工作都完成了再执行 DeleteGlobalRef//当然也可以通过加锁实现bool main_finished=false;bool background_finished=false;staticvoid*native_thread_exec(void*arg){LOGE(TAG,"nativeThreadExec");LOGE(TAG,"The pthread id : %d\n",pthread_self());JNIEnv*env;//从全局的JavaVM中获取到环境变量gJavaVM->AttachCurrentThread(&env,NULL);//线程循环for(inti=0;i<5;i++){usleep(2);//跨线程回调Java层函数env->CallVoidMethod(gJavaObj,nativeCallback,count++);}gJavaVM->DetachCurrentThread();background_finished=true;if(main_finished&&background_finished){env->DeleteGlobalRef(gJavaObj);LOGE(TAG,"全局引用在子线程销毁");}return((void*)0);}extern"C"JNIEXPORTvoidJNICALLJava_com_yuandaima_myjnidemo_MainActivity_threadTest(JNIEnv*env,jobject thiz){//创建全局引用,方便其他函数或线程使用gJavaObj=env->NewGlobalRef(thiz);jclass clazz=env->GetObjectClass(thiz);nativeCallback=env->GetMethodID(clazz,"javaCallback","(I)V");//保存全局 JavaVM,注意 JavaVM 不是 JNI 引用类型env->GetJavaVM(&gJavaVM);pthread_tid;if(pthread_create(&id,NULL,native_thread_exec,NULL)!=0){return;}for(inti=0;i<5;i++){usleep(20);//跨线程回调Java层函数env->CallVoidMethod(gJavaObj,nativeCallback,count++);}main_finished=true;if(main_finished&&background_finished&&!env->IsSameObject(gJavaObj,NULL)){env->DeleteGlobalRef(gJavaObj);LOGE(TAG,"全局引用在主线程销毁");}}

示例代码中,我们的子线程需要使用主线程中的jobject thiz,该变量是一个局部引用,不能赋值给一个全局变量然后跨线程跨函数使用,我们通过NewGlobalRef将局部引用装换为全局引用并保存在全局变量jobject gJavaObj中,在使用完成后我们需要使用DeleteGlobalRef来释放全局引用,因为多个线程执行顺序的不确定性,我们使用了标志位来确保两个线程所有的工作完成后再执行释放操作。

JNIEnv 是一个线程作用域的变量,不能跨线程传递,每个线程都有自己的 JNIEnv 且彼此独立,实际开发中,我们通过以下代码:在子线程中获取到 JNIEnv。

JavaVM*gJavaVM=NULL;//主线程获取到 JavaVMenv->GetJavaVM(&gJavaVM);//子线程通过 JavaVM 获取到自己的 JNIEnvJNIEnv*env;gJavaVM->AttachCurrentThread(&env,NULL);

JavaVM 是一个普通指针,由 JVM 来管理其内存的分配与回收,不是 JNI 引用类型,所以 我们可以把它赋值给一个全局变量,直接用,也不用考虑他的内存分配与后续问题。


版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 15:51:06

如何借助EOR名义雇主服务实现企业运营的top效益?

在全球扩张的过程中&#xff0c;企业需要考虑多种因素以保障高效运营。EOR名义雇主服务正是解决这些挑战的关键工具。通过这项服务&#xff0c;企业能够快速适应各个市场的法律法规&#xff0c;实现合规用工。同时&#xff0c;EOR名义雇主提供全方位的支持&#xff0c;无论是薪…

作者头像 李华
网站建设 2026/4/30 7:29:24

等保到底要花多少钱?别再被报价单吓到了

很多非安全背景的同事,一听等保,脑子里自动翻译成一句话: “请第三方来测一测,给个证,完事。” 但现实是,等保的钱主要花在 四个方向: 定级、备案、测评的钱(明面上的) 安全设备和软件的钱(大头) 系统整改的人力和改造成本(隐形但很贵) 后续运维和复测的长期成本(…

作者头像 李华
网站建设 2026/4/28 21:24:02

CAD中如何创建多行文字和文字编辑?

浩辰CAD看图王电脑版创建多行文字功能&#xff0c;可以很容易帮我们实现在图纸上记录大量的文字。可以是一段&#xff0c;也可以是多段&#xff0c;可详细记录内容。 今天就为大家简单介绍下浩辰CAD看图王电脑版如何创建多行文字的功能&#xff1f; 1、打开图纸&#xff0c;切…

作者头像 李华
网站建设 2026/5/1 1:28:36

Java后端打工人必备:Redis从入门到精通!

Redis这玩意不用多说&#xff0c;Java后端打工人就没有没接触过的&#xff0c;现在出去面试基本上是必问项&#xff1b;而且在工作中在项目中还能起很大的作用。它不仅能减少数据库的操作、并且你还可以利用redis的一些数据结构如set sorted set 解决一些特定的问题、利用单线程…

作者头像 李华
网站建设 2026/4/23 15:58:47

Java程序员须知:Spring全家桶学习顺序千万别搞错!

Spring可以说是我们Java入门时最先接触的框架了&#xff0c;只要你是Java程序员&#xff0c;它就是你绕不开必须要学习的一个点。对于我们这些有工作经验的Javaer来说&#xff0c;你不仅要学好Spring&#xff0c;还需要学好后续由它衍生一系列的框架组件&#xff08;我们一般把…

作者头像 李华
网站建设 2026/4/18 8:56:51

ArgoCD 中资源存在不可变字段修改的含义和举例

ArgoCD 中「资源存在不可变字段修改」具体指什么&#xff0c;还需要实际的示例来理解&#xff0c;我会先明确不可变字段的定义&#xff0c;再结合 K8s 常见资源给出具体示例&#xff08;覆盖高频场景&#xff09;&#xff0c;帮你直观理解。 一、先明确&#xff1a;什么是「不…

作者头像 李华