Java RMI y métodos sincronizados
concurrency synchronization (4)
Estás en lo correcto. El texto está mal. Los apéndices RMI son seguros para subprocesos y pueden ser invocados simultáneamente por múltiples subprocesos dentro de una JVM de un solo cliente. No tengo conocimiento de ninguna declaración o texto de Wollrath y todo lo que dice algo diferente, y he estado siguiendo este tema desde 1997.
Específicamente:
Lo que pensé es que el uso de un método sincronizado en una implementación de Objeto Remoto (por lo tanto, la implementación real que se ejecuta en el servidor) se evita la ejecución concurrente de ese método incluso cuando las llamadas a ese método son de diferentes máquinas clientes (llamando al método a través de un Proxy ... también conocido como un talón).
Estás en lo correcto.
En el libro, en cambio, se dice que la ejecución concurrente de métodos sincronizados no se evita cuando se usa RMI.
El libro no solo está equivocado, sino que está declarando una imposibilidad. ¿Cómo podría RMI evitar que la sincronización funcione?
Lógicamente, el bloqueo en un objeto remoto es simple. Supongamos que el cliente A llama a un método sincronizado de un objeto remoto.
Luego, el bloqueo se produce en el servidor, por el funcionamiento normal de Java.
Para que el acceso a los objetos remotos se vea exactamente igual a los objetos locales, sería necesario bloquear A en el código auxiliar del lado del cliente que implementa la interfaz del objeto y al que A tiene acceso directo.
Basura. El hecho de que la implementación del método remoto esté synchronized
hace todo lo necesario.
Del mismo modo, otro cliente en una máquina diferente también deberá bloquearse localmente antes de que su solicitud pueda enviarse al servidor.
Nuevamente esto es basura.
La consecuencia es que necesitamos sincronizar diferentes clientes en diferentes máquinas.
Basura de nuevo.
Un enfoque alternativo sería permitir el bloqueo solo en el servidor.
''Permitir''? ¿Qué significa esto? Se synchronized
método synchronized.
No puedes rechazarlo .
En principio, esto funciona bien, pero surgen problemas cuando un cliente se bloquea mientras el servidor maneja su invocación.
Nuevamente basura. No surgen tales problemas. El servidor se recupera de esta situación a través de un tiempo de espera de lectura o una excepción de escritura o incluso la finalización exitosa del método remoto. En los tres casos, el método sale, el bloqueo de sincronización se libera y la vida continúa.
Como discutimos en el cap. 8, podemos requerir protocolos relativamente sofisticados para manejar esta situación, y eso puede afectar significativamente el rendimiento general de las invocaciones de métodos remotos.
Disparates.
Por lo tanto, los diseñadores de Java RMI han optado por restringir el bloqueo en objetos remotos solo a los proxies (Wollrath et al., 1996).
No sé a qué otra cosa podría referirse esto que no sea el extracto que citó, y lo he leído muchas veces. Si los autores desean confiar en este documento, deberían haber proporcionado una cita y una cita adecuada para el capítulo y el versículo.
En cualquier caso, los diseñadores de RMI no hicieron tal elección. No había tal elección que hacer. synchronized
se synchronized
lo que sea que los diseñadores de RMI hayan deseado o no, y de manera similar, notify()
y wait()
son final.
No eran libres de hacer ninguna elección. La cita que proporcionó no es una "elección": es simplemente una afirmación sobre la semántica de Java.
¿Estoy interpretando el texto de forma incorrecta o de hecho se afirma que los métodos sincronizados "no están tan sincronizados" cuando se utiliza RMI?
Creo que lo estás leyendo correctamente, y está completamente equivocado, y no solo mal, sino que obviamente está equivocado. ¿Cómo podría ser correcto? Java RMI no puede, y de hecho no puede, alterar , eliminar o extender la semántica de synchronized
de ninguna manera.
Estoy estudiando el libro "Sistemas distribuidos" (por Tanenbaum y Van Steen) y dicen algo que parece estar en conflicto con lo que muchos piensan sobre el RMI de Java y los métodos sincronizados.
Lo que pensé es que el uso de un método sincronizado en una implementación de Objeto Remoto (por lo tanto, la implementación real que se ejecuta en el servidor) se evita la ejecución simultánea de ese método incluso cuando las llamadas a ese método son de máquinas de diferentes clientes ... también conocido como un talón).
He visto que muchas personas tienen la misma opinión, mire aquí, por ejemplo: preguntas sobre Java RMI y sincronización de subprocesos
En el libro, en cambio, se dice que la ejecución concurrente de métodos sincronizados no se evita cuando se usa RMI.
Aquí está el extracto relevante del libro (puede leer la oración en negrita solamente, pero puede leer el contexto si lo prefiere):
Lógicamente, el bloqueo en un objeto remoto es simple. Supongamos que el cliente A llama a un método sincronizado de un objeto remoto. Para que el acceso a los objetos remotos se vea exactamente igual a los objetos locales, sería necesario bloquear A en el código auxiliar del lado del cliente que implementa la interfaz del objeto y al que A tiene acceso directo. Del mismo modo, otro cliente en una máquina diferente también deberá bloquearse localmente antes de que su solicitud pueda enviarse al servidor. La consecuencia es que necesitamos sincronizar diferentes clientes en diferentes máquinas. Como discutimos en el cap. 6, la sincronización distribuida puede ser bastante compleja.
Un enfoque alternativo sería permitir el bloqueo solo en el servidor. En principio, esto funciona bien, pero surgen problemas cuando un cliente se bloquea mientras el servidor maneja su invocación. Como discutimos en el cap. 8, podemos requerir protocolos relativamente sofisticados para manejar esta situación, y eso puede afectar significativamente el rendimiento general de las invocaciones de métodos remotos.
Por lo tanto, los diseñadores de Java RMI han optado por restringir el bloqueo en objetos remotos solo a los proxies (Wollrath et al., 1996). Esto significa que se evitará que los subprocesos en el mismo proceso accedan simultáneamente al mismo objeto remoto, pero no lo harán los subprocesos en procesos diferentes. Obviamente, estas semánticas de sincronización son complicadas: a nivel sintáctico (es decir, al leer el código fuente) podemos ver un diseño agradable y limpio. Solo cuando la aplicación distribuida se ejecuta realmente, se puede observar un comportamiento imprevisto que debería haberse solucionado en el momento del diseño. [...]
Creo que el documento "Un modelo de objetos distribuidos para el sistema Java" ( disponible aquí ) está referenciado en el texto por la nota Wollrath et all, 1996
entre paréntesis. Sin embargo, el único párrafo relevante que he encontrado en ese documento es este:
Debido a los diferentes modos de falla de los objetos locales y remotos, la espera distribuida y la notificación requieren un protocolo más sofisticado entre las entidades involucradas (de modo que, por ejemplo, una falla del cliente no haga que un objeto remoto se bloquee para siempre), y como tal , no se puede ajustar fácilmente en el modelo de subprocesamiento local en Java. Por lo tanto, un cliente puede usar los métodos de notificación y espera en una referencia remota, pero ese cliente debe ser consciente de que tales acciones no involucrarán el objeto remoto real, solo el proxy local (stub) para el objeto remoto.
¿Estoy interpretando el texto de forma incorrecta o de hecho se afirma que los métodos sincronizados "no están tan sincronizados" cuando se utiliza RMI?
Lo que dice su primera referencia es que dentro de una sola instancia de máquina virtual, las invocaciones en un Stub de RMI (cliente a un servidor de RMI) se sincronizarán internamente. Es decir, el código auxiliar (o proxy, como parece llamarlo el texto) evitará que varios subprocesos invocen simultáneamente un método en el servidor remoto. Sin embargo, aclara que dos VMs, cada una con apéndices para un servidor remoto, no serán bloqueadas para invocar al servidor remoto (lo cual es obvio, ya que no pueden compartir un bloqueo y el RMI en sí mismo no evita la concurrencia en el servidor). Si esto no es deseable, el servidor RMI deberá implementar un mecanismo de bloqueo para evitar múltiples invocaciones simultáneas.
La segunda referencia no contradice de ninguna manera la primera. El segundo simplemente aclara que si intenta sincronizar en un código auxiliar, solo se bloqueará localmente y no afectará la concurrencia del servidor remoto.
Al combinar los dos textos, podemos leer que la sincronización en un stub evitará que los múltiples subprocesos en la misma VM accedan simultáneamente al control remoto, pero no evitará que los subprocesos en distintas VMs tengan acceso simultáneo.
Por lo que sé, cada llamada a un servidor RMI creará un nuevo hilo (atestiguado por mis archivos de registro desde 2000) en el lado del servidor. Si realiza la sincronización en el lado del servidor, debe estar seguro. Me enfrenté a algunas advertencias antiguas de la literatura como publicaste. Como practicante, preferí ejecutar el software durante aproximadamente un mes y decidí que era lo suficientemente estable para la producción. Lo siento si esto no es satisfactorio.
También debe tener en cuenta que los subprocesos múltiples de Java han cambiado significativamente desde 1996. Los métodos de notificación () y de espera () que formaban parte del diseño del idioma original obtuvieron una gran cantidad de expertos de concurrencia en Java 5 (2004, dice wiki ) se introdujeron objetos de concurrencia de alto nivel como ReentrantLock , que ahora son la forma preferida de hacer las cosas.
Así que las críticas que mencionas son probablemente correctas, pero desactualizadas.