Threads y Métodos Nativos

Java es un sistema multi-thread, por lo tanto los métodos nativos deben ser seguros con los threads, A menos que tengamos información extra (por ejemplo, si el método nativo está sincronizado), debemos asumir que pueden existir varios threads de control ejecutándose sobre un mismo método nativo en un momento dado. Por lo tanto, los métodos nativos no deberían modificar variables globales sensibles de una forma desprotegida. Esto es, deben compartir y coordinar su acceso a variables de ciertas secciones críticas de código.

Antes de leer esta sección, deberías estar familiarizado con los conceptos de threads de control y programas multi-threads. Threads de Control cubre la programación de threads. En particular, la página Programas Multi-Thread cubre elementos relacionados con la escritura de programas que contienen varios threads, incluyendo cómo sincronizarlos.

Los Threads y el JNI

El puntero al interface JNI (JNIEnv *) sólo es válido en el thread actual. Se debe pasar el puntero al intercace de un thread a otro, o guardar el puntero al interface y utilizarlo en varios threads. La máquina virtual Java pasa el mismo puntero al interface en llamadas sucesivas a un método nativo desde el mismo thread, pero diferentes threads pasan un diferente puntero al interface a los métodos nativos.

No se deben pasar referencias locales de un thread a otro. En particular, una referencia local se podría volver no válida antes de que otro thread tenga la posibilidad de utilizarla. Se deben convertir siempre en referencias globales cuando haya alguna duda sobre que una referencia a un objeto pueda ser uitlizada por threads diferentes.

Chequea el uso de variables globales cuidadosamente. Varios threads podrían acceder a las variables globales al mismo tiempo. Asegurate de que pones los bloqueos nocesarios para asegurar la seguridad.

Sincronización de Threads en Métodos Nativos.

El JNI proporciona dos funciones de sincronización que permiten implementar bloques sincronizados. En Java, son implementados utilizando la sentencia synchronized. Por ejemplo:
synchronized (obj) {
   ...                   /* synchronized block */
}
La Máquina Virtual Java garantiza que un thread deba adquirir el monitor asociado con el objeto Java obj antes de poder ejecutar las sentencias del bloque. Por lo tanto, en un momento dado, sólo puede haber un thread ejecutándose dentro del bloque sincronizado.

El código nativo puede realizar una sincronización equivalente de objetos utilizando las funciones del JNI MonitorEnter y MonitorExit. Por ejemplo:

(*env)->MonitorEnter(obj);
...                      /* synchronized block */
(*env)->MonitorExit(obj);
Un thread debe introducir el monitor asociado con obj antes de poder continuar con la ejecución. El monitor contiene un contador que señala cuantas veces ha sido introducido por un thread dado. MonitorEnter incrementa el contador cuando el thread entra un monitor que ya ha sido introducido. MonitorExit decrementa el contador. Si el contador alcanza el valor 0, otros threads pueden introducir el monitor.

Wait y Notify

Otro mecanismo de sincronización de threads es Object.wait, Object.notify, y Object.notifyAll. El JNI no soporta directamente estas funciones. Sin embargo, un método nativo puede seguir el mecanismo de llamada a métodos para invocar a estos métodos.

Ozito