2009-11-17 728 views
6

Me asignaron a trabajar en algunos problemas de rendimiento y bloqueo aleatorio de un servidor de Java multiproceso. Aunque los hilos y la seguridad de hilos no son realmente temas nuevos para mí, descubrí que diseñar una nueva aplicación de subprocesos múltiples es probablemente la mitad de difícil que tratar de modificar algún código heredado. Repasé algunos libros bien conocidos en busca de respuestas, pero lo extraño es que, mientras lo lea y analice los ejemplos proporcionados, todo parece claro. Sin embargo, en el momento en que veo el código en el que se supone que debo trabajar, ¡ya no estoy seguro de nada! Debe haber demasiado conocimiento teórico y poca experiencia en el mundo real o algo así.Subprocesos separados para entrada y salida de socket

De todos modos, volviendo al tema, como estaba haciendo algunas investigaciones en línea, me encontré con this piece of code. La pregunta que me sigue molestando es: ¿Es realmente seguro invocar getInputStream() y getOutputStream() en el socket desde dos hilos separados sin sincronización? ¿O me estoy volviendo un poco demasiado paranoico con respecto a todo el tema de seguridad de subprocesos? Supongo que eso es lo que sucede cuando, al igual que el quinto libro consecutivo, te dice cuántas cosas pueden salir mal con la concurrencia.

PS. Lo siento si la pregunta es un poco larga o tal vez demasiado "noobie", por favor sea amable conmigo, esa es mi primera publicación aquí.

Edición: Para que quede claro, sé que los sockets funcionan en modo dúplex completo y es seguro utilizar al mismo tiempo sus flujos de entrada y salida. Me parece bien cuando adquiere esas referencias en el hilo principal y luego inicializa los objetos del hilo con esas, pero ¿también es seguro para obtener esas secuencias en dos hilos diferentes?

@rsp:

Así que he comprobado el código del Sol y PlainSocketImpl se sincronizaba en esos dos métodos, tal como dijiste. Socket, sin embargo, no. getInputStream() y getOutputStream() son prácticamente envolturas para SocketImpl, por lo que probablemente problemas de concurrencia no causarían la explosión del servidor completo. Aún así, con un poco de sincronización desafortunada, parece que las cosas podrían fallar (por ejemplo, cuando otro subproceso cierra el socket cuando el método ya verificó las condiciones de error).

Como ha señalado, desde el punto de vista de la estructura del código, sería una buena idea proporcionar a cada hilo una referencia de flujo en lugar de un socket completo. Probablemente ya haya reestructurado el código en el que estoy trabajando si no fuera por el hecho de que cada subproceso también usa el método close() de socket (por ejemplo, cuando el socket recibe el comando "shutdown"). Por lo que puedo decir, el propósito principal de esos hilos es poner mensajes en cola para enviar o procesar, por lo que tal vez sea una violación del Principio de Responsabilidad Individual y esos hilos no deberían poder cerrar el zócalo (compárese con Separated Modem Interface). Pero si continúo analizando el código por mucho tiempo, parece que el diseño es generalmente defectuoso y todo requiere una nueva redacción. Incluso si la administración estuviera dispuesta a pagar el precio, seriamente refactorizar el código heredado, no tener pruebas de unidad alguna vez y lidiar con problemas de concurrencia difíciles de depurar, probablemente haría más daño que bien. ¿No es así?

Respuesta

3

El flujo de entrada y el flujo de salida del socket representan dos flujos de datos o canales separados. Es perfectamente guardar usando ambas secuencias en hilos que no están sincronizados entre ellos. Las secuencias de sockets bloquearán la lectura y escritura en buffers vacíos o llenos.

Editar: las clases de implementación de socket de sol haga sychronize los métodos getInputStream() y getOutputStream(), llamando a continuación, a partir de diferentes hilos deben estar bien. Sin embargo, estoy de acuerdo con usted en que pasar las secuencias a los hilos que las usan puede tener más sentido desde el punto de vista de la estructura del código (por ejemplo, la inyección de dependencia ayuda a probar).

Cuestiones relacionadas