SINCRONIZACIÓN DE THREADS
Una situación común en programas con
múltiples threads es cuando dos threads comparten o tienen acceso a
un solo recurso, como un archivo, la conexión de base de datos o un
objeto. Esta situación puede provocar situaciones de error o
inconsistencia de datos.
Para garantizar que sólo un thread
ejecutará una sección crítica de código, evitar la inconsistencia
de datos y errores, los mecanismos de sincronización deben de
implementarse.
Java provee dos mecanismos de
sincronización:
- La palabra clave synchronized.
- La interfaz java.util.concurrent.locks.Lock y sus implementaciones.
Cada objeto en java tiene de defecto un
lock, que sólo entra en juego cuando el objeto tenga sincronizado un
bloque de código.
Si un thread tiene el lock de un
objeto, ningún otro thread puede tener el lock hasta que el primer
thread lo libere. Un thread puede adquirir más de una lock.
Ejemplo:
public class Resource {
public synchronized void lock() {
System.out.println(“Begining, the thread ” + Thread.currentThread().getName() + “has the lock”);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(“Ending, the thread ” + Thread.currentThread().getName() + “has the lock”);
}
}
public class Concurrent extends Thread {
Resource resource;
public Concurrent( Resource resource, String name) {
super(name);
this. resource = resource;
}
public void run(){
resource.lock();
}
}
.....
Resource resource = new Resource();
Concurrent c1 = new Concurrent(resource, “one”);
c1.start();
Concurrent c2 = new Concurrent(resource, “two”);
c2.start();
......
En el ejemplo anterior dos threads acceden concurrentemente un
recurso, pero un thread tiene que esperar al otro a que termine de
utilizar al recurso ya que el recurso está protegido por la palabra
clave synchronized, no hay garantía de que thread adquirirá el
recurso primero.
Los mensajes en la consola deben de aparecer de la siguiente manera:
Comenzando, el thread uno tiene el lock
Finalizando, el thread uno tiene el lock
Comenzando, el thread dos tiene el lock
Finalizando, el thread dos tiene el lock
o
Comenzando, el thread dos tiene el lock
Finalizando, el thread dos tiene el lock
Comenzando, el thread uno tiene el lock
Finalizando, el thread uno tiene el lock
Los mensajes para cada thread aparecen consecutivamente y no se
mezclan, ya que cada thread no libera el lock del objeto Recurso
hasta que termina de ejecutar el método lock ().
Si la palabra clave synchronized se retira de la declaración de la
lock () en la clase Recurso, los resultados del programa podría ser
cualquiera, un ejemplo de los mensajes en la consola sería:
Comenzando, el thread dos tiene el lock
Comenzando, el thread uno tiene el lock
Finalizando, el thread uno tiene el lock
Finalizando, el thread dos tiene el lock
La palabra clave synchronized se puede aplicar a una instancia de un
objeto para proteger el acceso de un bloque de código en lugar de un
método, tiene el mismo comportamiento, el thread que accesa el
bloque de de código intenta adquirir el lock del objeto.
Ejemplo:
public class Recurso {
public void lock() {
synchronized(this) {
System.out.println(“Comenzando, el thread ” + Thread.currentThread().getName() + “tiene el lock”);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(“Finalizando, el thread ” + Thread.currentThread().getName() + “tien el lock”);
}
}
}
........
El otro mecanismo de sincronización proporcionada por Java es la
interfaz Lock y sus implementaciones, de acuerdo con la API de Java
“las implementaciones de Lock proporcionan más operaciones que
las que pueden obtenerse utilizando métodos y sentencias
sincronizadas. Permiten una estructuración más flexible, puede
tener propiedades muy diferentes, y puede soportar múltiples objetos
de tipo Condition asociados ".
La interfaz Lock proporciona varios métodos para obtener un Lock de
un objeto con diferentes comportamientos.
El siguiente ejemplo es el mismo que el utilizado anteriormente con
la palabra clave synchronized.
Ejemplo:
public class Recurso {
Lock objetoLock = new ReentrantLock();
public void lock() {
objetoLock.lock();//Adquiere el lock
System.out.println(“Comenzando, el thread ” + Thread.currentThread().getName() + “tiene el lock”);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(“Finalizando, el thread ” + Thread.currentThread().getName() + “tiene el lock”);
objetoLock.unlock();//Libera el lock
}
}
.......
En el ejemplo se utilizó la implementación ReentrantLock de la
interfaz Lock, pero la API proporciona más implementaciones con
diferente comportamiento de cada una.
ReentrantLock tiene otro constructor que acepta un parámetro
booleano conocido como el parámetro fair, y si es falso indica que
cualquier thread que espera por el Lock lo recibirá, pero si es
verdadero
indica que el thread que ha estado esperando el mayor tiempo por el
Lock lo recibirá.
Lock lock = new ReentrantLock(true);//fair es verdadero
El método lock() intenta adquirir el lock del objeto Lock, si
otro thread tiene el lock del objeto, el thread esperara hasta que el
thread que tiene el lock lo libere.
Cuando un thread termina de usar un lock debe llamar al método
unlock() para liberar el lock para que otros thread pueden
acceder al lock.
La interfaz Lock tiene le método tryLock(), y este es similar
al método lock(), pero este método no se bloquea esperando un lock
como el método lock() lo hace, este devuelve un valor booleano que
indica si el lock fue adquirido o no, devuelve verdedero si la lock
estaba libre y fue adquirido por el falso actual, y false en caso
contrario.
Este método debe ser usado en una condición if(), si se obtiene el
lock entonces un bloque de código se ejecutara.
If (objetoLock.tryLock()) {
.........
Harrah's Cherokee Casino & Hotel - Mapyro
ReplyDeleteHarrah's Cherokee Casino & Hotel. 777 Casino 전라북도 출장마사지 Center Dr. Cherokee, 상주 출장마사지 NC 28719. Directions · 상주 출장마사지 (828) 영주 출장마사지 276-7777. Call Now · More Info. Hours, Accepts Credit Cards, Wi-Fi, Rating: 4.2 세종특별자치 출장마사지 · 1,523 reviews