Saltar al contenido

Ejemplo de evitar interbloqueo

Estate atento ya que en este enunciado encontrarás el hallazgo que buscas.

Solución:

Ordenar las cuentas. El punto muerto proviene del ordenamiento de las cuentas (a,b vs b,a).

Así que prueba:

 public static void transfer(Account from, Account to, double amount)
      Account first = from;
      Account second = to;
      if (first.compareTo(second) < 0) 
          // Swap them
          first = to;
          second = from;
      
      synchronized(first)
           synchronized(second)
                from.withdraw(amount);
                to.deposit(amount);
           
      
 

Además de la solución de bloqueo ordenado, también puede evitar el bloqueo mutuo sincronizando en un privado static objeto de bloqueo final antes de realizar cualquier transferencia de cuenta.

 class Account{
 double balance;
 int id;
 private static final Object lock = new Object();
  ....




 public static void transfer(Account from, Account to, double amount)
          synchronized(lock)
          
                    from.withdraw(amount);
                    to.deposit(amount);
          
     

Esta solución tiene el problema de que un privado static lock restringe el sistema a realizar transferencias "secuencialmente".

Otro puede ser si cada Cuenta tiene un ReentrantLock:

private final Lock lock = new ReentrantLock();




public static void transfer(Account from, Account to, double amount)
{
       while(true)
        
          if(from.lock.tryLock())
            try  
                if (to.lock.tryLock())
                   try
                       from.withdraw(amount);
                       to.deposit(amount);
                       break;
                    
                   finally 
                       to.lock.unlock();
                   
                
           
           finally 
                from.lock.unlock();
           

           int n = number.nextInt(1000);
           int TIME = 1000 + n; // 1 second + random delay to prevent livelock
           Thread.sleep(TIME);
        

 

No se produce interbloqueo en este enfoque porque esos bloqueos nunca se mantendrán indefinidamente. Si se adquiere el bloqueo del objeto actual pero el segundo bloqueo no está disponible, el primer bloqueo se libera y el subproceso duerme durante un período de tiempo específico antes de intentar volver a adquirir el bloqueo.

Esta es una pregunta clásica. Veo dos posibles soluciones:

  1. Para ordenar cuentas y sincronizar en la cuenta que tiene una identificación más baja que otra. Este método se menciona en la biblia de concurrencia Java Concurrency in Practice en el capítulo 10. En este libro, los autores usan el código hash del sistema para distinguir las cuentas. Consulte java.lang.System#identityHashCode.
  2. Usted menciona la segunda solución: sí, puede evitar los bloques sincronizados anidados y su código no conducirá a un punto muerto. Pero en ese caso, el procesamiento puede tener algunos problemas porque si retira dinero de la primera cuenta, la segunda cuenta puede quedar bloqueada durante un tiempo significativo y probablemente tendrá que devolver dinero a la primera cuenta. Eso no es bueno y porque esa sincronización anidada y el bloqueo de dos cuentas es una solución mejor y más utilizada.
¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

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