Llamadas simultaneas al mismo método
Hola,
He creado una clase que gestiona envios por un socket, siguiendo el patron singleton. Para hacer el envio, la clase tiene un metodo que es el encargado de mandar por el socket lo que recibe como parámetro.
La cosa es, que multiples hilos tomarán la instancia vigente de la clase (singleton), para llamar a ese método y hacer el envio de datos por el socket. Entonces, no se si esto plantea problemas de concurrencia y que se produzcan bloqueos por acceder al mismo método del mismo objeto paralelamente, ya que además este envÃa por el mismo socket.
Supongo que sÃ, ya que se podrÃan mezlcar mensajes.
¿¿Como serÃa una forma eficiente y sencilla de hacer esto?? ... me gustarÃa seguir manteniendo el uso del patron para tener el "gestor de envios" bien definido y siendo único.
Muchas gracias
Pedro
He creado una clase que gestiona envios por un socket, siguiendo el patron singleton. Para hacer el envio, la clase tiene un metodo que es el encargado de mandar por el socket lo que recibe como parámetro.
La cosa es, que multiples hilos tomarán la instancia vigente de la clase (singleton), para llamar a ese método y hacer el envio de datos por el socket. Entonces, no se si esto plantea problemas de concurrencia y que se produzcan bloqueos por acceder al mismo método del mismo objeto paralelamente, ya que además este envÃa por el mismo socket.
Supongo que sÃ, ya que se podrÃan mezlcar mensajes.
¿¿Como serÃa una forma eficiente y sencilla de hacer esto?? ... me gustarÃa seguir manteniendo el uso del patron para tener el "gestor de envios" bien definido y siendo único.
Muchas gracias
Pedro
Buenas:
En principio no hay problema con lo que es el código en sÃ. El problema es usar el mismo socket. Si dos hilos envÃan mensajes a la vez, es posibles que los bytes de ambos mensajes salgan entremezclados por el socket. El que va a recibir no se enterará de nada, le llegan cosas raras.
Pasa lo mismo con la lectura. Si dos hilos intentan leer a la vez, es posible que cada uno consiga un cacho del mensaje.
Todo esto es más probable cuanto más grandes sean los mensajes.
Para evitarlo, dentro de la clase que envia y recibe del socket, tendras una instancia de Socket o algo similar. Al leer o recibir mensajes ahi dentro, hazlo asi
public Object dameMensaje()
{
synchronized (instanciaSocket)
{
// codigo para leer un mensaje completo
}
return mensaje
}
public void enviaMensaje (Object mensaje)
{
synchronized (instanciaSocket)
{
// codigo para enviar el mensaje completo.
}
}
Una pequeña tonterÃa. Los sockets son bidireccionales. Un hilo podrÃa leer un mensaje y otro enviar a la vez. Si lo haces como te estoy diciendo, eliminas esa posibilidad. Si tienes interés en que se pueda hacer a la vez, en vez de usar instanciaSocket, tendrÃas que usar para sincronizar los inputStream y outputStream que obtienes del socket que es con los que realmente escribes.
Se bueno.
En principio no hay problema con lo que es el código en sÃ. El problema es usar el mismo socket. Si dos hilos envÃan mensajes a la vez, es posibles que los bytes de ambos mensajes salgan entremezclados por el socket. El que va a recibir no se enterará de nada, le llegan cosas raras.
Pasa lo mismo con la lectura. Si dos hilos intentan leer a la vez, es posible que cada uno consiga un cacho del mensaje.
Todo esto es más probable cuanto más grandes sean los mensajes.
Para evitarlo, dentro de la clase que envia y recibe del socket, tendras una instancia de Socket o algo similar. Al leer o recibir mensajes ahi dentro, hazlo asi
public Object dameMensaje()
{
synchronized (instanciaSocket)
{
// codigo para leer un mensaje completo
}
return mensaje
}
public void enviaMensaje (Object mensaje)
{
synchronized (instanciaSocket)
{
// codigo para enviar el mensaje completo.
}
}
Una pequeña tonterÃa. Los sockets son bidireccionales. Un hilo podrÃa leer un mensaje y otro enviar a la vez. Si lo haces como te estoy diciendo, eliminas esa posibilidad. Si tienes interés en que se pueda hacer a la vez, en vez de usar instanciaSocket, tendrÃas que usar para sincronizar los inputStream y outputStream que obtienes del socket que es con los que realmente escribes.
Se bueno.
Creo que voy a optar por sincronizar el metodo que hace los envios. En cuanto a envÃo-recepcion no hay problema, porque el socket solo se usará para mandar informacion.
El metodo queda algo asÃ:
public synchronized void send(Message message)
{
envio = new BufferedWriter(new OutputStreamWriter(socketEnvios));
try
{
envio.write(message);
envio.flush();
}
catch (IOException e)
{
System.err.println("Error");
}
}
Asà cada hilo que quiera enviar un mensaje, si el metodo está ocupado tendrán que esperar ...
¿Todo bien, no???
Muchas gracias a los dos.
El metodo queda algo asÃ:
public synchronized void send(Message message)
{
envio = new BufferedWriter(new OutputStreamWriter(socketEnvios));
try
{
envio.write(message);
envio.flush();
}
catch (IOException e)
{
System.err.println("Error");
}
}
Asà cada hilo que quiera enviar un mensaje, si el metodo está ocupado tendrán que esperar ...
¿Todo bien, no???
Muchas gracias a los dos.
