When you get array elements through a Get<Type>ArrayElements call, you must think about synchronization.

Whether the data is pinned or not, two entities are involved in accessing the data:
  • The Java™ code in which the data entity is declared and used
  • The native code that accesses the data through the JNI

These two entities are probably separate threads, in which case contention occurs.

Consider the following scenario in a copying JNI implementation:
  1. A Java program creates a large array and partially fills it with data.
  2. The Java program calls native write function to write the data to a socket.
  3. The JNI native that implements write() calls GetByteArrayElements.
  4. GetByteArrayElements copies the contents of the array into a buffer, and returns it to the native.
  5. The JNI native starts writing a region from the buffer to the socket.
  6. While the thread is busy writing, another thread (Java or native) runs and copies more data into the array (outside the region that is being written).
  7. The JNI native completes writing the region to the socket.
  8. The JNI native calls ReleaseByteArrayElements with mode 0, to indicate that it has completed its operation with the array.
  9. The VM, seeing mode 0, copies back the whole contents of the buffer to the array, and overwrites the data that was written by the second thread.

In this particular scenario, the code works with a pinning JVM. Because each thread writes only its own bit of the data and the mode flag is ignored, no contention occurs. This scenario is another example of how code that is not written strictly to specification works with one JVM implementation and not with another. Although this scenario involves an array elements copy, pinned data can also be corrupted when two threads access it at the same time.

Be careful about how you synchronize access to array elements. You can use the JNI interfaces to access regions of Java arrays and strings to reduce problems in this type of interaction. In the scenario, the thread that is writing the data writes into its own region. The thread that is reading the data reads only its own region. This method works with every JNI implementation.