martes, 3 de septiembre de 2019

Programación segura en java (Thread safe)


Cuando hablamos de seguridad en hilos nos referimos a un concepto de programación aplicable en el contexto de los programas multihilos. Se considera a una pieza de código como segura, en cuanto a los hilos, si funciona correctamente durante la ejecución simultánea de múltiples hilos. En particular, debe satisfacer la necesidad de que múltiples hilos accedan a los mismos datos compartidos, y la necesidad de que una pieza compartida de datos sea accedida por solo un hilo en un momento dado.

Pregunta de entrevista:

¿El siguiente método es seguro para subprocesos?

class MyCounter {
 private static int counter = 0;
 
 public static int getCount() {
  return counter++;
 }
}

En primer lugar, la respuesta es NO. El método no es seguro para subprocesos, porque la operación counter ++ no es atómica, lo que significa que consta de más de una operación atómica.

En este caso, uno hilo accede al valor y el otro aumenta el valor en uno.



Cuando el subproceso 1 accede al método en t1, el subproceso 2 no se puede hacer con el método, por lo tanto, el valor devuelto al subproceso 1 es el valor que no se ha aumentado.

Java admite el concepto de programas concurrentes o multiproceso. La unidad básica de concurrencia es un hilo, y varios hilos pueden ejecutarse dentro de un solo programa. Es bastante habitual que los hilos accedan a una estructura de datos común. En dicho acceso, es posible que un hilo interrumpa la operación de lectura de otro hilo, para hacer su propia actualización o eliminación. Si no se gestiona adecuadamente ¡esto puede traducirse en resultados inesperados!

Los podemos ver mas claramente en el siguiente ejemplo:

¿Que debemos tener en cuenta a la hora de programar usando multiples hilos?
  • Nunca manipular variables de instancia sin un mecanismo que asegure operaciones atómicas.
  • Si accedemos a un metodo que manipula una variable de instancia dicho metodo debe ser declarado con el modificador "synchronized" de manera tal que nos aseguremos que un sólo subproceso a la vez pueda acceder a la funcion.La palabra synchronized indica que un método puede ser accedido por un solo hilo a la vez. Synchronized puede ser aplicado solo a métodos, ni a variables, ni a clases, solo a métodos. Un ejemplo típico de synchronized sería parecido a esto:
    1
    2
    public synchronized Record retrieveUserInfo(int id){}
    Deberíamos tambien saber que el modificador synchronized puede ser complementado con cualquiera de los 4 niveles de control de acceso.
  • Usar objetos y rutinas de java que aseguren que nuestro programa sea thread safe por ejemplo:
    • ConcurrentHashMap:
      •  Mantendrá el bloqueo a nivel de segmento. Tiene 16 segmentos y mantiene el nivel de concurrencia como 16 por defecto. Entonces, a la vez, 16 subprocesos pueden funcionar en ConcurrentHashMap. Además, la operación de lectura no requiere un bloqueo. Entonces, cualquier número de subprocesos puede realizar una operación de obtención en él.Si thread1 quiere realizar la operación put en el segmento 2 y thread2 quiere realizar la operación put en el segmento 4, entonces está permitido aquí. Significa que 16 subprocesos pueden realizar operaciones de actualización (put / delete) en ConcurrentHashMap a la vez.Para que el tiempo de espera sea menor aquí. Por lo tanto, el rendimiento es relativamente mejor que el Hashmap sincronizado.
El siguiente grafico muestra que es una variable de instancia:

El siguiente grafico describe que mapas son seguros y cual es su performance/tipo de acceso:


Como podemos ver en el grafico, el concurrentHashMap funciona con segmentos, el lockeo de hilos es siempre a nivel segmento, lo que permite concurrencia en tiempos de ejecución y mejora considerablemente la performance de un mapa sincronizado o de una rutina que utilice el modificador de sincronización.



Programación segura en java (Thread safe)

Cuando hablamos de seguridad en hilos nos referimos a un concepto de programación aplicable en el contexto de los programas multihilos. S...