Marco de bloqueo frente a sincronización de subprocesos en Java

El mecanismo de sincronización de subprocesos se puede lograr utilizando el marco de bloqueo, que está presente en el paquete java.util.concurrent . El marco de bloqueo funciona como bloques sincronizados, excepto que los bloqueos pueden ser más sofisticados que los bloques sincronizados de Java. Los bloqueos permiten una estructuración más flexible del código sincronizado. Este nuevo enfoque se introdujo en Java 5 para abordar el problema de sincronización mencionado a continuación.

Veamos una clase Vector, que tiene muchos métodos sincronizados. Cuando hay 100 métodos sincronizados en una clase, solo se puede ejecutar un subproceso de estos 100 métodos en un momento dado. Solo se permite que un subproceso acceda a un solo método en un momento determinado mediante un bloque sincronizado. Esta es una operación muy costosa. Los bloqueos evitan esto al permitir la configuración de varios bloqueos para diferentes propósitos. Uno puede tener un par de métodos sincronizados bajo un bloqueo y otros métodos bajo un bloqueo diferente. Esto permite una mayor concurrencia y también aumenta el rendimiento general.

Ejemplo: 

Lock lock = new ReentrantLock();
lock.lock();

// Critical section
lock.unlock();

Un bloqueo se adquiere mediante el método lock() y se libera mediante el método unlock(). Invocar un unlock() sin lock() generará una excepción. Como ya se mencionó, la interfaz de bloqueo está presente en el paquete java.util.concurrent.locks y ReentrantLock implementa la interfaz de bloqueo. 

Nota: El número de llamadas lock() siempre debe ser igual al número de llamadas unlock().

En el siguiente código, el usuario ha creado un recurso llamado «TestResource» que tiene dos métodos y dos bloqueos diferentes para cada uno respectivamente. Hay dos trabajos llamados «DisplayJob» y «ReadJob». La clase LockTest crea 5 subprocesos para realizar ‘DisplayJob’ y 5 subprocesos para realizar ‘ReadJob’. Los 10 subprocesos comparten un solo recurso «TestResource».

Java

import java.util.Date;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
 
// Test class to test the lock example
// 5 threads are created with DisplayJob
// and 5 thread are created with ReadJob.
// Both these jobs use single TestResource named "test".
public class LockTest
{
    public static void main(String[] args)
    {
        TestResource test = new TestResource();
        Thread thread[] = new Thread[10];
          for (int i = 0; i < 5; i++)
          {
             thread[i] = new Thread(new DisplayJob(test),
             "Thread " + i);
          }
          for (int i = 5; i < 10; i++)
          {
             thread[i] = new Thread(new ReadJob(test),
             "Thread " + i);
          }
          for (int i = 0; i < 10; i++)
          {
             thread[i].start();
          }
    }
 
}
// DisplayJob class implementing Runnable interface.
// This uses TestResource object passed in the constructor.
// run method invokes displayRecord method on TestResource.
class DisplayJob implements Runnable
{
     
    private TestResource test;
    DisplayJob(TestResource tr)
    {
        test = tr;
    }
    @Override
    public void run()
    {
        System.out.println("display job");
        test.displayRecord(new Object());
    }
}
// ReadJob class implementing Runnable interface.
// which uses TestResource object passed in the constructor.
// run method invokes readRecord method on TestResource.
class ReadJob implements Runnable
{
     
    private TestResource test;
     
    ReadJob(TestResource tr)
    {
        test = tr;
    }
    @Override
    public void run()
    {
        System.out.println("read job");
        test.readRecord(new Object());
    }
}
// Class which has two locks and two methods.
 
class TestResource
{
     
    // displayQueueLock is created to make
    // displayQueueLock thread safe.
    // When T1 acquires lock on testresource(o1)
    // object displayRecord method
    // T2 has to wait for lock to be released
    // by T1 on testresource(o1) object
    // displayRecord method.  But T3, can execute 
    // readRecord method with out waiting for lock
    // to be released by t1 as
    // readRecord method uses readQueueLock not
    // displayQueueLock.
    private final Lock
    displayQueueLock = new ReentrantLock();
    private final Lock
    readQueueLock = new ReentrantLock();
 
    // displayRecord uses displayQueueLock to
    // achieve thread safety.
    public void displayRecord(Object document)
    {
        final Lock displayLock = this.displayQueueLock;
        displayLock.lock();
        try
          {
             Long duration =
                         (long) (Math.random() * 10000);
             System.out.println(Thread.currentThread().
             getName() + ": TestResource: display a Job"+
             " during " + (duration / 1000) + " seconds ::"+
             " Time - " + new Date());
             Thread.sleep(duration);
          }
          catch (InterruptedException e)
          {
             e.printStackTrace();
          }
          finally
          {
             System.out.printf("%s: The document has been"+
             " dispalyed\n", Thread.currentThread().getName());
             displayLock.unlock();
          }
    }
 
    // readRecord uses readQueueLock to achieve thread safety.   
    public void readRecord(Object document)
    {
        final Lock readQueueLock = this.readQueueLock;
        readQueueLock.lock();
        try
          {
             Long duration =
                       (long) (Math.random() * 10000);
             System.out.println
             (Thread.currentThread().getName()
             + ": TestResource: reading a Job during " +
             (duration / 1000) + " seconds :: Time - " +
             new Date());
             Thread.sleep(duration);
          }
          catch (InterruptedException e)
          {
             e.printStackTrace();
          }
          finally
          {
             System.out.printf("%s: The document has"+
             " been read\n", Thread.currentThread().getName());
             readQueueLock.unlock();
          }
    }
}

Salida

trabajo 
de visualización trabajo 
de visualización trabajo de visualización trabajo de 
visualización trabajo de 
visualización trabajo de 
lectura trabajo  de
lectura trabajo  de
lectura trabajo  de
lectura trabajo  de
lectura 
Subproceso 5: TestResource: lectura de un trabajo durante 4 segundos::Hora: miércoles 27 de febrero a las 15:49:53 UTC 2019 
Subproceso 0: TestResource: mostrar un Trabajo durante 6 segundos::Hora – Mié 27 de febrero 15:49:53 UTC 2019 
Subproceso 5: El documento ha sido leído 
Subproceso 6: TestResource: leyendo un Trabajo durante 4 segundos::Hora – Mié 27 de febrero 15:49: 58 UTC 2019 
 

En el ejemplo anterior, DisplayJob no requiere esperar a que los subprocesos ReadJob completen la tarea, ya que ReadJob y Display job utilizan dos bloqueos diferentes. Esto no puede ser posible con «sincronizado».

Las diferencias son las siguientes:  

Parámetros Marco de bloqueo sincronizado
A través de métodos Sí, los bloqueos se pueden implementar en todos los métodos, puede invocar lock() en el método 1 e invocar unlock() en el método 2. Imposible
tratar de adquirir bloqueo sí, el método de bloqueo (tiempo de espera) es compatible con el marco de bloqueo, que bloqueará el recurso si está disponible; de ​​lo contrario, devuelve falso y Thread no se bloqueará. No es posible con sincronizado
Gestión de bloqueo justo Sí, la gestión de bloqueo justo está disponible en caso de marco de bloqueo. Entrega la cerradura a un largo hilo de espera. Incluso en el modo de equidad establecido en verdadero, si se codifica el bloqueo de prueba, se sirve primero. No es posible con sincronizado
Lista de hilos en espera Sí, la lista de subprocesos en espera se puede ver usando el marco de bloqueo No es posible con sincronizado
Liberación de bloqueo en excepciones
Lock.lock(); myMethod();Lock.unlock();

unlock() no se puede ejecutar en este código si se lanza alguna excepción desde myMethod().

Synchronized funciona claramente en este caso. Libera la cerradura

Publicación traducida automáticamente

Artículo escrito por haripriyapendem y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *