同步

通过 Get<Type>ArrayElements 调用获取数组元素时,必须考虑同步问题。

无论数据是否已固定,在访问数据时都涉及以下这两个实体:
  • 在其中声明和使用数据实体的 Java™ 代码
  • 通过 JNI 访问数据的本机代码

这两个实体可能是单独的线程,在这种情况下会发生争用。

在复制 JNI 实现时请考虑以下场景:
  1. Java 程序创建一个大数组,并在其中部分填充数据。
  2. Java 程序调用本机写函数以将数据写入套接字。
  3. 实现 write() 的 JNI 本机将调用 GetByteArrayElements。
  4. GetByteArrayElements 将数组的内容复制到缓冲区,并将其返回到本机。
  5. JNI 本机启动将区域从缓冲区写入套接字。
  6. 当线程忙于写入时,另一个线程 (Java 或本机) 将运行并将更多数据复制到数组中 (正在写入的区域外部)。
  7. JNI 本机完成将区域写入套接字。
  8. JNI 本机使用方式 0 调用 ReleaseByteArrayElements,以表示它已完成有关数组的操作。
  9. VM(请参见方式 0)将缓冲区的整个内容复制回数组,并覆盖第二个线程写入的数据。

在此特定场景中,代码用于固定的 JVM。 由于每个线程仅写入其自己的数据位,并且将忽略方式标志,因此不会发生任何争用。 该场景是另一个如何将未严格写入规范的代码用于一个 JVM 实现而不用于另一个实现的示例。 虽然此场景涉及数组元素副本,但是在两个线程同时访问固定的数据时,这些数据仍可能被破坏。

请注意如何同步访问数组元素。 您可以使用 JNI 接口来访问 Java 数组和字符串的区域,以减少此类交互中的问题。 在此场景中,写入数据的线程将写入其自己的区域。 读取数据的线程仅读取它自己的区域。 此方法用于每个 JNI 实现。