Synchronisation

Wenn Sie Array-Elemente über einen Get<Type>ArrayElements-Aufruf erhalten, müssen Sie über die Synchronisierung nachdenken.

Unabhängig davon, ob die Daten eine feste Adresse erhalten oder nicht, sind stets zwei Entitäten in den Zugriff auf Daten einbezogen:
  • Der Java™ -Code, in dem die Datenentität deklariert und verwendet wird.
  • Der native Code, der über das JNI auf die Daten zugreift

Diese beiden Entitäten sind wahrscheinlich separate Threads, woraufhin es dann zu einer Konkurrenzsituation kommt.

Betrachten Sie das folgende Szenario in einer kopierenden JNI-Implementierung:
  1. Ein Java-Programm erstellt ein großes Array und füllt es teilweise mit Daten.
  2. Das Java-Programm ruft die native Schreibfunktion auf, um die Daten in ein Socket zu schreiben.
  3. Der native JNI-Code, der write() implementiert, ruft 'GetByteArrayElements' auf.
  4. 'GetByteArrayElements' kopiert den Inhalt des Arrays in einen Puffer und gibt ihn an den nativen Code zurück.
  5. Der native JNI-Code beginnt mit dem Schreiben eines Bereichs aus dem Puffer in den Socket.
  6. Während der Thread mit dem Schreiben beschäftigt ist, wird ein anderer Thread (Java oder nativ) ausgeführt und kopiert weitere Daten in das Array (außerhalb der zu schreibenden Region).
  7. Der native JNI-Code beendet das Schreiben der Region in den Socket.
  8. Der native JNI-Code ruft 'ReleaseByteArrayElements' mit dem Modus 0 auf, um anzugeben, dass er die Operation am Array abgeschlossen hat.
  9. Die VM erkennt den Modus 0, kopiert den gesamten Inhalt des Puffers in das Array und überschreibt die Daten, die vom zweiten Thread geschrieben worden waren.

In diesem speziellen Szenario arbeitet der Code mit einer JVM mit festen Speicheradressen. Weil jeder Thread nur seinen eigenen Teil der Daten schreibt und die Modusmarkierung ignoriert wird, tritt kein Konflikt auf. Dieses Szenario ist ein weiteres Beispiel dafür, wie Code, der nicht strikt spezifikationsgemäß geschrieben ist, bei der einen JVM-Implementierung funktioniert, bei einer anderen hingegen nicht. Zwar bezieht dieses Szenario ein Kopieren der Array-Elemente ein, doch können Daten mit festen Speicheradressen auch beschädigt werden, wenn zwei Threads gleichzeitig darauf zugreifen.

Gehen Sie beim Synchronisieren des Zugriffs auf Array-Elemente mit Umsicht vor. Mithilfe der JNI-Schnittstellen können Sie auf Regionen von Java-Arrays und -Zeichenfolgen zugreifen, um Probleme bei dieser Art von Interaktion zu reduzieren. Im Szenario schreibt der Thread, der die Daten schreibt, diese in seine eigene Region. Der Thread, der die Daten liest, liest nur seine eigene Region. Diese Methode funktioniert bei jeder JNI-Implementierung.