Monday, May 13, 2013

Concurrencia en Java Parte 3

Esta es la tercera parte del tutorial, este link te lleva al  post anterior concurrencia en java parte-2


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()) {
                                .........
                          }

Ir a parte 4

1 comment:

  1. Harrah's Cherokee Casino & Hotel - Mapyro
    Harrah'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

    ReplyDelete