A continuación se describen una serie de Clases que hacen uso del concepto de Sincronización en "Threads" .
public class CampoDeTiro { public static void main(String[] args) { Pistola arma = new Pistola(); Cargar c = new Cargar(arma, 1); Descargar d = new Descargar(arma, 1); c.start(); d.start(); } } |
Primeramente se define una Clase ejecutable que contiene las declaraciones necesarias para invocar las Clases diseñadas con "Threads".
Una vez definido el método principal main
se genera una instancia de la Clase Pistola
.
Posteriormente se generan instancias de las Clases Cargar
y Descargar
, nótese que estas declaraciones toman como parámetro de entrada la instancia de la Clase Pistola
definida con anterioridad.
Finalmente, se invoca el método run()
sobre las instancias de las Clases Cargar
y Descargar
, dicho método corresponde al clásico método necesario para activar "Threads".
public class Pistola { private int cartucho; private boolean enposicion = true; public synchronized void disparar(int cartucho) { while (enposicion == false) { try { // Esperar a apuntar wait(); } catch (InterruptedException e) { } } enposicion = false; notifyAll(); } public synchronized void apuntar() { while (enposicion == true) { try { // Esperar a disparar wait(); } catch (InterruptedException e) { } } enposicion = true; notifyAll(); } } |
Definida la Clase, se declaran dos campos ("fields"), uno de tipo int
y otro boolean
.
Posteriormente se definen dos métodos llamados disparar
y apuntar
, estos métodos contienen el calificador synchronized
empleado en la sincronización de "Threads".
Significado/Uso de
|
En ambos métodos (disparar
y apuntar
) se evalúa el valor del campo enposicion
, y en base al valor de éste se entra en un bloque try/catch
invocando el método wait
de "Threads", para posteriormente modificar el campo y finalmente invocar el método notifyAll
para notificar a todo "Thread" la terminación del método y por ende la liberación ("lock") sobre la instancia del Objeto.
public class Cargar extends Thread { private Pistola arma; private int cartucho; public Cargar(Pistola arma, int cartucho) { this.arma = arma; this.cartucho = cartucho; } public void run() { for (int i = 0; i < 10; i++) { arma.apuntar(); System.out.println("Apuntar #" + this.cartucho + " bala: " + i); } } } |
Se define la Clase principal que hereda ("inherit") el comportamiento de java.lang.Thread
.
Posteriormente se definen dos campos, seguidos de un constructor empleado en la asignación de estos valores.
Finalmente se reimplementa ("Override") el método run()
, para que contenga una ciclo, así como invocar el método apuntar()
(De la Clase Pistola
) e imprimir un mensaje a la consola.
public class Descargar extends Thread { private Pistola arma; private int cartucho; public Descargar(Pistola arma, int cartucho) { this.arma = arma; this.cartucho = cartucho; } public void run() { for (int i = 0; i < 10; i++) { arma.disparar(i); System.out.println("Descargar #" + this.cartucho + " bala: " + i); } } } |
Se define la Clase principal que hereda ("inherit") el comportamiento de java.lang.Thread
.
Posteriormente se definen dos campos, seguidos de un constructor empleado en la asignación de estos valores.
Finalmente se reimplementa ("Override") el método run()
, para que contenga una ciclo, así como invocar el método disparar()
(De la Clase Pistola
) e imprimir un mensaje a la consola.
Al ejecutar la Clase CampoDeTiro
se estarían ejecutando dos "Threads" simultáneamente, sin embargo, a diferencia del ejemplo descrito anteriormente notará que el orden de ejecución será llevado acabo de manera ordenada, esto es, el resultado producido siempre será idéntico.
Lo anterior se debe al uso del vocablo synchronized
y los diversos eventos disponibles para manipulación de "Threads" (notifyAll
y wait
).