Curso Java. Volumen II. Regiones críticas

Curso Java. Volumen II. Regiones críticas

Sergio De Luz

En la primera parte de Introducción a la Concurrencia os explicamos las regiones críticas, y el problema que presenta el uso de las variables compartidas.

Para evitar que la corrección del programa se vea comprometido, podemos usar un método de Java, el método synchronized. Este método se encarga de controlar el acceso a dicha variable compartida.

A continuación, os explicamos con ejemplos el problema.

Vamos a tener 20 hilos, que accederán a una varible y van a hacer un simple +1, es decir, aumentar en 1 el valor de dicha variable.

Tenemos el siguiente código con su programa principal, podéis copiar y pegar en una clase.java llamada SumResta y funcionará correctamente

[java]class algo {

static int suma = 0;
static void anadir() {
suma++;
System.out.println("SUMA: " + suma);
}
}

class Hilos extends Thread {

@Override
public void run() {
algo.anadir();
}
}

public class SumResta {

public static void main(String[] args) {
try {
for (int i = 0; i < 10; i++) {
Hilos h = new Hilos();
Hilos h1 = new Hilos();
h.start();
h1.start();
}
} catch (Exception e) {
}
}
}[/java]

La salida que obtenemos por pantalla es la siguiente:

SUMA: 2
SUMA: 3
SUMA: 2
SUMA: 4
SUMA: 5
SUMA: 6
SUMA: 7
SUMA: 8
SUMA: 9
SUMA: 10
SUMA: 11
SUMA: 12
SUMA: 13
SUMA: 14
SUMA: 15
SUMA: 16
SUMA: 17
SUMA: 18
SUMA: 19
SUMA: 20

En teoría, deberían salir totalmente colocados de forma secuencial. Cada vez que ejecutemos el programa el resultado cambiará. Una de los requisitos de la programación concurrente es que el resultado debe ser independiente del número de hilos, por lo que este resultado debería estar de forma secuencial. Si el programa tuviera más hilos, y nuestro equipo varios núcleos, los resultados serían mucho más dispares.

Para corregir esto, basta con usar el método synchronized en la variable compartida, o en el propio método. Normalmente siempre se usa en el método.

[java]class algo {

static int suma = 0;
static synchronized void anadir() {
suma++;
System.out.println("SUMA: " + suma);
}
}

class Hilos extends Thread {

@Override
public void run() {
algo.anadir();
}
}

public class SumResta {

public static void main(String[] args) {
try {
for (int i = 0; i < 10; i++) {
Hilos h = new Hilos();
Hilos h1 = new Hilos();
h.start();
h1.start();
}
} catch (Exception e) {
}
}
}[/java]

Y la salida de dicho programa será esta:

SUMA: 1
SUMA: 2
SUMA: 3
SUMA: 4
SUMA: 5
SUMA: 6
SUMA: 7
SUMA: 8
SUMA: 9
SUMA: 10
SUMA: 11
SUMA: 12
SUMA: 13
SUMA: 14
SUMA: 15
SUMA: 16
SUMA: 17
SUMA: 18
SUMA: 19
SUMA: 20

Como podéis ver, aparece el número 1, no hay repeticiones y se realiza de forma secuencial. Por muchos hilos que tengamos, el resultado será el mismo, estamos ante un programa correcto.

El método synchronized se usa para que el acceso a la variable sea único, es decir, sólo halla un hilo, podríamos decir que realmente se hace de forma secuencial pero en programas grandes, mientras un hilo está en la región crítica, el otro estará haciendo otro tipo de acción por lo que ganaríamos tiempo.

En el próximo volumen, pondremos otro ejemplo de regiones críticas pero bastante más grande y sobre todo, útil, ya que esto ha sido simplemente una iniciación para que veáis qué ocurre si no tomamos las medidas necesarias…el programa falla.

1 Comentario