【问题标题】:Native multithreading and JNI原生多线程和 JNI
【发布时间】:2023-03-25 11:55:01
【问题描述】:

我有一个 Android 应用程序,它由一些需要能够调用 Java 对象的方法的本机线程(未附加到 JVM)组成。

我打算这样做的方式是创建一个 JNI 函数,我从相关的 Java 对象调用它,它允许我获取并缓存所需的 Java 对象方法 ID、JNIEnv 和静态本机数据中的对象引用结构,以便我的本机线程可以(线程安全地)访问所需的方法(例如使用 (*env)->CallVoidMethod(env, this, JavaMethodID, ...) 等;

我不相信这种方法会奏效,因为我读到 JNIEnv 指针不能在线程之间共享,并且只有附加到 JVM 的线程才能做这种事情......

这是一种可行的方法吗?

【问题讨论】:

标签: android java-native-interface


【解决方案1】:
  1. JNI_OnLoad,缓存JavaVM*。这是唯一在线程间持久且有效的东西。
  2. 一旦你设置了一些本机线程,调用AttachCurrentThread并获取JNIEnv*,它只对那个单线程有效。
  3. 使用JavaVM*JNIEnv*,查找您的jclasses、jobjects 和jmethodIDs。 这些仍然只对你附加的单个线程有效。
  4. jclasses 和jobjects 转换为全局引用,以便它在线程间持续存在。 jmethodIDs 不需要全球化,它们不是工作对象。
  5. 在任何其他本机线程上,您需要再次调用 AttachCurrentThread 以获取该线程的有效 JNIEnv*
  6. 当您不再需要创建的全局引用时,不要忘记删除它们(最迟在JNI_OnUnload

【讨论】:

  • 谢谢帕维尔,这正是我正在寻找的东西。澄清一下,一旦我缓存了方法 ID 并全球化了我的类和对象引用,所有后续线程都可以使用相同的方法 ID(例如在 CallVoidMethod() 中),前提是它们通过自己的 JNIEnv* 这样做,如您在 5 中描述的那样。我不必为每个线程获取一组新的方法 ID,是吗?
  • 是的,方法 ID 在任何地方都有效。只有引用类型才需要“全球化”,即从 jobject 派生的任何东西。 jmethodID 不是作业对象,它是“opaque structure”。我的理论是,它只是类函数表的某种序数索引(如 C++ 的 vtable),因此对于类的所有实例都是相同的。
  • 太好了,再次感谢。我会将您的答案投票为“有用”,但还没有足够的声誉。
  • @Jenix field ID 是一个不透明的结构,如 method ID。底层实现预期不同,但跨线程的可用性是相同的。我之前评论中的链接已失效,newer-ish here
  • @Jenix 了解线程之间不能共享的内容可能会更好——jobject 的子类。 Android specific documentation here。根据这个定义,methodID 和 fieldID 不需要任何特殊的保护,因为它只是一些值类型,而不是引用类型。
猜你喜欢
  • 2012-02-26
  • 1970-01-01
  • 1970-01-01
  • 2014-12-06
  • 1970-01-01
  • 1970-01-01
  • 2021-07-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多