Exemplos de deadlock simples


92

Eu gostaria de explicar os bloqueios de threading para iniciantes. Já vi muitos exemplos de deadlocks no passado, alguns usando código e outros usando ilustrações (como os famosos 4 carros ). Existem também problemas clássicos de fácil impasse, como The Dining Philosophers , mas eles podem ser complexos demais para um verdadeiro novato compreender totalmente.

Estou procurando o exemplo de código mais simples para ilustrar o que são deadlocks. O exemplo deve:

  1. Relacione-se com um cenário de programação "real" que faz algum sentido
  2. Seja muito curto, simples e direto

O que você recomenda?


por que não usar os famosos 4 carros, pois me parece bastante simples.
vehomzzz

2
Os 4 carros não são um cenário de programação e não é trivial para um novato abstrair um problema na forma dos 4 carros. Eu os uso, mas quero mostrar um cenário de programação onde ocorre um impasse.
Roee Adler

Respostas:


139

Talvez uma situação bancária simples.

class Account {
  double balance;

  void withdraw(double amount){
     balance -= amount;
  } 

  void deposit(double amount){
     balance += amount;
  } 

   void transfer(Account from, Account to, double amount){
        sync(from);
        sync(to);

        from.withdraw(amount);
        to.deposit(amount);

        release(to);
        release(from);
    }

}

Obviamente, se houver duas threads que tentam executar a transferência ( a, b ) e a transferência ( b, a ) ao mesmo tempo, um deadlock ocorrerá porque elas tentam adquirir os recursos na ordem inversa.

Este código também é ótimo para procurar soluções para o impasse. Espero que isto ajude!


1
Seria perfeito se você ou outra pessoa pudesse dar a solução para esse problema.
Jacky

2
@Jacky A solução para este problema foi postada por Will Hartung aqui: stackoverflow.com/questions/13326861/avoid-deadlock-example/…
Piotr Chojnacki

2
Estou confuso com sua sintaxe. Qual é o método sync ()? Eu entenderia se sync (from); ... release (from); foram substituídos por synchronized (from) {...}
Ellen Spertus

1
@espertus syncpode ser algo como: sync(Account & a) { a.mutex.lock(); }.
vladon

1
javaworld.com/article/2075692/java-concurrency/… (Brian Goetz) explica a solução para este problema.
lingareddyk

59

Deixe a natureza explicar o impasse,

Impasse: Frog vs. Snake

"Eu adoraria vê-los seguir caminhos separados, mas estava exausto", disse o fotógrafo. “O sapo ficava o tempo todo tentando puxar a cobra, mas a cobra não largava” .

insira a descrição da imagem aqui


59
Bonito, mas não explica como os deadlocks ocorrem em um contexto de programação.
jalf

ok jalf, pelo menos você justificou o downvote. De qualquer forma, é semelhante ao exemplo dos "4 carros". Uma representação fofa de como é um impasse.
Nick Dandoulakis

@Nick Dandoulakis: Excelente apresentação pictórica. Imagem explica o conceito de impasse
Rasmi Ranjan Nayak

@NickDandoulakis - Não é um bom exemplo de imagem, imho. Um código simples seria útil aqui.
Erran Morad

13
Como isso deveria ser BONITO? Cobras e sapos venenosos estão comendo uns aos outros e é assustador !!!
vikkyhacks

53

Aqui está um exemplo de código do departamento de ciência da computação de uma universidade em Taiwan, mostrando um exemplo simples em java com bloqueio de recursos. Isso é muito relevante para a "vida real" para mim. Código abaixo:

/**
 * Adapted from The Java Tutorial
 * Second Edition by Campione, M. and
 * Walrath, K.Addison-Wesley 1998
 */

/**
 * This is a demonstration of how NOT to write multi-threaded programs.
 * It is a program that purposely causes deadlock between two threads that
 * are both trying to acquire locks for the same two resources.
 * To avoid this sort of deadlock when locking multiple resources, all threads
 * should always acquire their locks in the same order.
 **/
public class Deadlock {
  public static void main(String[] args){
    //These are the two resource objects 
    //we'll try to get locks for
    final Object resource1 = "resource1";
    final Object resource2 = "resource2";
    //Here's the first thread.
    //It tries to lock resource1 then resource2
    Thread t1 = new Thread() {
      public void run() {
        //Lock resource 1
        synchronized(resource1){
          System.out.println("Thread 1: locked resource 1");
          //Pause for a bit, simulating some file I/O or 
          //something. Basically, we just want to give the 
          //other thread a chance to run. Threads and deadlock
          //are asynchronous things, but we're trying to force 
          //deadlock to happen here...
          try{ 
            Thread.sleep(50); 
          } catch (InterruptedException e) {}

          //Now wait 'till we can get a lock on resource 2
          synchronized(resource2){
            System.out.println("Thread 1: locked resource 2");
          }
        }
      }
    };

    //Here's the second thread.  
    //It tries to lock resource2 then resource1
    Thread t2 = new Thread(){
      public void run(){
        //This thread locks resource 2 right away
        synchronized(resource2){
          System.out.println("Thread 2: locked resource 2");
          //Then it pauses, for the same reason as the first 
          //thread does
          try{
            Thread.sleep(50); 
          } catch (InterruptedException e){}

          //Then it tries to lock resource1.  
          //But wait!  Thread 1 locked resource1, and 
          //won't release it till it gets a lock on resource2.  
          //This thread holds the lock on resource2, and won't
          //release it till it gets resource1.  
          //We're at an impasse. Neither thread can run, 
          //and the program freezes up.
          synchronized(resource1){
            System.out.println("Thread 2: locked resource 1");
          }
        }
      }
    };

    //Start the two threads. 
    //If all goes as planned, deadlock will occur, 
    //and the program will never exit.
    t1.start(); 
    t2.start();
  }
}

1
O problema é que não é realmente um exemplo da "vida real". É sobre "recurso 1" e "recurso 2", e seria bom relacionar isso a um problema real de programação (quero dizer, diretamente utilizável na prática, com referência ao domínio do problema etc.)
Jay

7
Bom exemplo na minha opinião. Obrigado.
James Raitsev

Este código parece ter sido publicado em alguns livros diferentes ... stackoverflow.com/a/11338853/112705
Dan J

15

Se method1 () e method2 () serão chamados por dois ou mais threads, há uma boa chance de deadlock porque se thread 1 adquirir bloqueio no objeto String durante a execução do método1 () e thread 2 adquirir bloqueio no objeto Integer durante a execução do método2 () ambos estarão esperando um ao outro para liberar o bloqueio de Integer e String para prosseguir, o que nunca acontecerá.

public void method1() {
    synchronized (String.class) {
        System.out.println("Acquired lock on String.class object");

        synchronized (Integer.class) {
            System.out.println("Acquired lock on Integer.class object");
        }
    }
}

public void method2() {
    synchronized (Integer.class) {
        System.out.println("Acquired lock on Integer.class object");

        synchronized (String.class) {
            System.out.println("Acquired lock on String.class object");
        }
    }
}

Rápido e simples. Agradável.
user1068352

13

Um dos exemplos de impasse simples que encontrei.

public class SimpleDeadLock {
   public static Object l1 = new Object();
   public static Object l2 = new Object();
   private int index;
   public static void main(String[] a) {
      Thread t1 = new Thread1();
      Thread t2 = new Thread2();
      t1.start();
      t2.start();
   }
   private static class Thread1 extends Thread {
      public void run() {
         synchronized (l1) {
            System.out.println("Thread 1: Holding lock 1...");
            try { Thread.sleep(10); }
            catch (InterruptedException e) {}
            System.out.println("Thread 1: Waiting for lock 2...");
            synchronized (l2) {
               System.out.println("Thread 2: Holding lock 1 & 2...");
            }
         }
      }
   }
   private static class Thread2 extends Thread {
      public void run() {
         synchronized (l2) {
            System.out.println("Thread 2: Holding lock 2...");
            try { Thread.sleep(10); }
            catch (InterruptedException e) {}
            System.out.println("Thread 2: Waiting for lock 1...");
            synchronized (l1) {
               System.out.println("Thread 2: Holding lock 2 & 1...");
            }
         }
      }
   }
}

Eu gosto desse exemplo. Mas por que a classe SimpleDeadLock sai de Thread? Isso não é necessário.
Charmin

1
Isso é praticamente a mesma coisa que esta resposta: stackoverflow.com/a/1385868/1310566 . E o que isso está private int indexfazendo aí?
Simon Forsberg,

6

Aqui está um exemplo simples em C ++ 11.

#include <mutex>    // mutex
#include <iostream> // cout 
#include <cstdio>   // getchar
#include <thread>   // this_thread, yield
#include <future>   // async
#include <chrono>   // seconds

using namespace std;
mutex _m1;
mutex _m2;

// Deadlock will occur because func12 and func21 acquires the two locks in reverse order

void func12()
{
    unique_lock<mutex> l1(_m1);
    this_thread::yield(); // hint to reschedule
    this_thread::sleep_for( chrono::seconds(1) );
    unique_lock<mutex> l2(_m2 );
}

void func21()
{
    unique_lock<mutex> l2(_m2);
    this_thread::yield(); // hint to reschedule
    this_thread::sleep_for( chrono::seconds(1) );
    unique_lock<mutex> l1(_m1);
}

int main( int argc, char* argv[] )
{
    async(func12);
    func21();
    cout << "All done!"; // this won't be executed because of deadlock
    getchar();
}

5

Por favor, veja minha resposta a esta pergunta . Resultado final, sempre que dois threads precisam adquirir dois recursos diferentes, e o fazem em ordens diferentes, você pode obter impasses.


2
Realmente não vejo sentido em duplicar as informações de outra resposta aqui. Presumo que, se você acha que esta resposta pode ser melhorada, você está livre para editá-la.
djna

Acho que essa situação é chamada de "inversão de bloqueio". Bem, eu sei que é chamado de inversão de bloqueio, porque eu o chamo assim, mas acho que esse também é o termo da arte para isso :-)
Steve Jessop

4

Um exemplo em que posso pensar é o cenário Mesa, Lanterna e Baterias. Imagine uma lanterna e um par de baterias colocados em cima de uma mesa. Se você fosse até esta mesa e pegasse as baterias enquanto outra pessoa está com a lanterna, vocês dois seriam forçados a se olharem sem jeito enquanto esperam por quem colocará seu item de volta na mesa. Este é um exemplo de impasse. Você e a pessoa estão esperando por recursos, mas nenhum de vocês está desistindo de seus recursos.

Da mesma forma, em um programa, o deadlock ocorre quando dois ou mais threads (você e a outra pessoa) estão esperando que duas ou mais travas (lanterna e baterias) sejam liberadas e as circunstâncias no programa são tais que as travas nunca são liberadas ( vocês dois têm uma peça do quebra-cabeça).

Se você conhece java, é assim que pode representar esse problema:

import java.util.concurrent.locks.*;

public class Deadlock1 {

    public static class Table {

        private static Lock Flashlight = new ReentrantLock();
        private static Lock Batteries = new ReentrantLock();        

        public static void giveFlashLightAndBatteries() {
            try {
                Flashlight.lock();
                Batteries.lock();
                System.out.println("Lights on");
            } finally {
                Batteries.unlock();
                Flashlight.unlock();
            }
        }

        public static void giveBatteriesAndFlashLight() {
            try {
                Batteries.lock();
                Flashlight.lock();
                System.out.println("Lights on");
            } finally {
                Flashlight.unlock();
                Batteries.unlock();
            }
        }
    }

    public static void main(String[] args) {
        // This thread represents person one
        new Thread(new Runnable() {
            public void run() { Table.giveFlashLightAndBatteries(); }
        }).start();

        // This thread represents person two
        new Thread(new Runnable() {
            public void run() { Table.giveBatteriesAndFlashLight(); }
        }).start();
    }
}

Se você executar este exemplo, notará que às vezes as coisas funcionam bem e corretamente. Mas às vezes seu programa simplesmente não imprime nada. Isso porque uma pessoa está com as pilhas e outra com a lanterna, o que impede que acendam a lanterna causando um travamento.

Este exemplo é semelhante ao exemplo dado pelos tutoriais java: http://docs.oracle.com/javase/tutorial/essential/concurrency/deadlock.html

Outro exemplo é o exemplo de loop:

public class Deadlock2 {

    public static class Loop {
        private static boolean done = false;

        public static synchronized void startLoop() throws InterruptedException {
            while(!done) {
                Thread.sleep(1000);
                System.out.println("Not done");
            }
        }

        public static synchronized void stopLoop() {
            done = true;
        }

    }

    public static void main(String[] args) {
        // This thread starts the loop
        new Thread(new Runnable() {
            public void run() {
                try {
                    Loop.startLoop();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        // This thread stops the loop
        new Thread(new Runnable() {
            public void run() {
                Loop.stopLoop();
            }
        }).start();
    }
}

Este exemplo pode imprimir 'Não feito' repetidamente ou nunca pode imprimir 'Não feito'. O primeiro acontece porque o primeiro thread adquire o bloqueio de classe e nunca o libera, evitando que 'stopLoop' seja acessado pelo segundo thread. E o mais recente acontece porque o segundo encadeamento foi iniciado antes do primeiro encadeamento, fazendo com que a variável 'concluído' fosse verdadeira antes de o primeiro encadeamento ser executado.


4
public class DeadLock {
    public static void main(String[] args) throws InterruptedException {
        Thread mainThread = Thread.currentThread();
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    mainThread.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread1.start();
        thread1.join();
    }
}

3

No entanto, considero o problema dos Dining Philosophers um dos exemplos mais simples em mostrar impasses, uma vez que os 4 requisitos de impasse podem ser facilmente ilustrados pelo desenho (especialmente a espera circular).

Considero os exemplos do mundo real muito mais confusos para o novato, embora não consiga pensar em um bom cenário do mundo real de cabeça agora (sou relativamente inexperiente com simultaneidade no mundo real).


3

Recentemente percebi que as brigas entre casais não passam de um impasse .. onde normalmente um dos processos tem que travar para resolvê-lo, é claro que é o de menor prioridade (Menino;)).

Aqui está a analogia ...

Processo1: Menina (G) Processo2: Menino (B) Recurso1: Desculpe Recurso2
: Aceitando o próprio erro

Condições necessárias:
1. Exclusão mútua: Apenas um de G ou B pode pedir desculpas ou aceitar o próprio erro de cada vez.
2. Hold and Wait: Em um momento, um está segurando Desculpe e outro Aceitando o próprio erro, um está esperando Aceitando o próprio erro para liberar desculpe, e outro está aguardando desculpas para liberar aceitando o próprio erro.
3. Sem preempção: Nem mesmo Deus pode forçar B ou G a liberar Desculpe ou Aceitar o próprio erro. E voluntariamente? Você está brincando comigo??
4. Espera circular: Mais uma vez, aquele que está segurando o arrependimento espera que o outro aceite os próprios erros, e um que está segurando aceita os próprios erros quer que o outro se desculpe primeiro. Portanto, é circular.

Portanto, os impasses ocorrem quando todas essas condições estão em vigor ao mesmo tempo, e esse é sempre o caso em uma briga de casal;)

Fonte: http://www.quora.com/Saurabh-Pandey-3/Posts/Never-ending-couple-fights-a-deadlock


3

Mais um exemplo de deadlock simples com dois recursos diferentes e dois encadeamentos aguardando um ao outro para liberar o recurso. Diretamente de examples.oreilly.com/jenut/Deadlock.java

 public class Deadlock {
  public static void main(String[] args) {
    // These are the two resource objects we'll try to get locks for
    final Object resource1 = "resource1";
    final Object resource2 = "resource2";
    // Here's the first thread.  It tries to lock resource1 then resource2
    Thread t1 = new Thread() {
      public void run() {
        // Lock resource 1
        synchronized(resource1) {
          System.out.println("Thread 1: locked resource 1");

          // Pause for a bit, simulating some file I/O or something.  
          // Basically, we just want to give the other thread a chance to
          // run.  Threads and deadlock are asynchronous things, but we're
          // trying to force deadlock to happen here...
          try { Thread.sleep(50); } catch (InterruptedException e) {}

          // Now wait 'till we can get a lock on resource 2
          synchronized(resource2) {
            System.out.println("Thread 1: locked resource 2");
          }
        }
      }
    };

    // Here's the second thread.  It tries to lock resource2 then resource1
    Thread t2 = new Thread() {
      public void run() {
        // This thread locks resource 2 right away
        synchronized(resource2) {
          System.out.println("Thread 2: locked resource 2");

          // Then it pauses, for the same reason as the first thread does
          try { Thread.sleep(50); } catch (InterruptedException e) {}

          // Then it tries to lock resource1.  But wait!  Thread 1 locked
          // resource1, and won't release it 'till it gets a lock on
          // resource2.  This thread holds the lock on resource2, and won't
          // release it 'till it gets resource1.  We're at an impasse. Neither
          // thread can run, and the program freezes up.
          synchronized(resource1) {
            System.out.println("Thread 2: locked resource 1");
          }
        }
      }
    };

    // Start the two threads. If all goes as planned, deadlock will occur, 
    // and the program will never exit.
    t1.start(); 
    t2.start();
  }
}

If all goes as planned, deadlock will occur, and the program will never exit.Podemos fazer este exemplo de guaranteedeadlock?
Erran Morad de

Este é o mesmo código que Kyle postou , por que adicionar uma resposta duplicada três anos após a outra? (e por que eu comento sobre isso, mais três anos depois?)
Simon Forsberg

2

O impasse pode ocorrer em uma situação em que um Girl1está querendo flertar com Guy2quem é pego por outro Girl2e Girl2quer flertar com um Guy1que é pego por Girl1. Visto que ambas as meninas estão esperando para se livrar uma da outra, a condição é chamada de impasse.

class OuchTheGirls
{
    public static void main(String[] args)
    {
        final String resource1 = "Guy1";
        final String resource2 = "Guy2";

        // Girl1 tries to lock resource1 then resource2
        Thread Girl1 = new Thread(() ->
                                  {
                                      synchronized (resource1)
                                      {
                                          System.out.println("Thread 1: locked Guy1");

                                          try { Thread.sleep(100);} catch (Exception e) {}

                                          synchronized (resource2)
                                          {
                                              System.out.println("Thread 1: locked Guy2");
                                          }
                                      }
                                  });

        // Girl2 tries to lock Guy2 then Guy1
        Thread Girl2 = new Thread(() ->
                                  {
                                      synchronized (resource2)
                                      {
                                          System.out.println("Thread 2: locked Guy2");

                                          try { Thread.sleep(100);} catch (Exception e) {}

                                          synchronized (resource1)
                                          {
                                              System.out.println("Thread 2: locked Guy1");
                                          }
                                      }
                                  });


        Girl1.start();
        Girl2.start();
    }
}


1

Vá para o cenário possível simplista em que pode ocorrer um impasse ao apresentar o conceito para seus alunos. Isso envolveria um mínimo de dois threads e um mínimo de dois recursos (eu acho). O objetivo é projetar um cenário em que o primeiro encadeamento tem um bloqueio no recurso um e está esperando que o bloqueio no recurso dois seja liberado, enquanto ao mesmo tempo o encadeamento dois mantém um bloqueio no recurso dois e está esperando por o bloqueio no recurso um a ser liberado.

Não importa realmente quais são os recursos subjacentes; para simplificar, você pode apenas torná-los um par de arquivos nos quais ambos os threads podem gravar.

EDITAR: Isso pressupõe que não haja comunicação entre processos além dos bloqueios mantidos.


1

Achei um pouco difícil de entender ao ler o problema dos filósofos de jantar, impasse IMHO está realmente relacionado à alocação de recursos. Gostaria de compartilhar um exemplo mais simples onde 2 Enfermeiros precisam lutar por 3 equipamentos para completar uma tarefa. Embora seja escrito em java. Um método lock () simples é criado para simular como o deadlock acontece, para que possa ser aplicado em outra linguagem de programação também. http://www.justexample.com/wp/example-of-deadlock/


1

Exemplo simples de https://docs.oracle.com/javase/tutorial/essential/concurrency/deadlock.html

public class Deadlock {

public static void printMessage(String message) {

    System.out.println(String.format("%s %s ", Thread.currentThread().getName(), message));

}

private static class Friend {

    private String name;

    public Friend(String name) {
        this.name = name;
    }

    public void bow(Friend friend) {

        printMessage("Acquiring lock on " + this.name);

        synchronized(this) {
            printMessage("Acquired lock on " + this.name);
            printMessage(name + " bows " + friend.name);
            friend.bowBack(this);
        }

    }

    public void bowBack(Friend friend) {

        printMessage("Acquiring lock on " + this.name);

        synchronized (this) {
            printMessage("Acquired lock on " + this.name);
            printMessage(friend.name + " bows back");
        }

    }

}

public static void main(String[] args) throws InterruptedException {

    Friend one = new Friend("one");
    Friend two = new Friend("two");

    new Thread(new Runnable() {
        @Override
        public void run() {
            one.bow(two);
        }
    }).start();

    new Thread(new Runnable() {
        @Override
        public void run() {
            two.bow(one);
        }
    }).start();
}

}

Resultado:

Thread-0 Acquiring lock on one 
Thread-1 Acquiring lock on two 
Thread-0 Acquired lock on one 
Thread-1 Acquired lock on two 
Thread-1 two bows one 
Thread-0 one bows two 
Thread-1 Acquiring lock on one 
Thread-0 Acquiring lock on two 

Despejo de discussão:

2016-03-14 12:20:09
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.74-b02 mixed mode):

"DestroyJavaVM" #13 prio=5 os_prio=0 tid=0x00007f472400a000 nid=0x3783 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Thread-1" #12 prio=5 os_prio=0 tid=0x00007f472420d800 nid=0x37a3 waiting for monitor entry [0x00007f46e89a5000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at com.anantha.algorithms.ThreadJoin$Friend.bowBack(ThreadJoin.java:102)
    - waiting to lock <0x000000076d0583a0> (a com.anantha.algorithms.ThreadJoin$Friend)
    at com.anantha.algorithms.ThreadJoin$Friend.bow(ThreadJoin.java:92)
    - locked <0x000000076d0583e0> (a com.anantha.algorithms.ThreadJoin$Friend)
    at com.anantha.algorithms.ThreadJoin$2.run(ThreadJoin.java:141)
    at java.lang.Thread.run(Thread.java:745)

"Thread-0" #11 prio=5 os_prio=0 tid=0x00007f472420b800 nid=0x37a2 waiting for monitor entry [0x00007f46e8aa6000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at com.anantha.algorithms.ThreadJoin$Friend.bowBack(ThreadJoin.java:102)
    - waiting to lock <0x000000076d0583e0> (a com.anantha.algorithms.ThreadJoin$Friend)
    at com.anantha.algorithms.ThreadJoin$Friend.bow(ThreadJoin.java:92)
    - locked <0x000000076d0583a0> (a com.anantha.algorithms.ThreadJoin$Friend)
    at com.anantha.algorithms.ThreadJoin$1.run(ThreadJoin.java:134)
    at java.lang.Thread.run(Thread.java:745)

"Monitor Ctrl-Break" #10 daemon prio=5 os_prio=0 tid=0x00007f4724211000 nid=0x37a1 runnable [0x00007f46e8def000]
   java.lang.Thread.State: RUNNABLE
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
    at java.net.SocketInputStream.read(SocketInputStream.java:170)
    at java.net.SocketInputStream.read(SocketInputStream.java:141)
    at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
    at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
    - locked <0x000000076d20afb8> (a java.io.InputStreamReader)
    at java.io.InputStreamReader.read(InputStreamReader.java:184)
    at java.io.BufferedReader.fill(BufferedReader.java:161)
    at java.io.BufferedReader.readLine(BufferedReader.java:324)
    - locked <0x000000076d20afb8> (a java.io.InputStreamReader)
    at java.io.BufferedReader.readLine(BufferedReader.java:389)
    at com.intellij.rt.execution.application.AppMain$1.run(AppMain.java:93)
    at java.lang.Thread.run(Thread.java:745)

"Service Thread" #9 daemon prio=9 os_prio=0 tid=0x00007f47240c9800 nid=0x3794 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C1 CompilerThread3" #8 daemon prio=9 os_prio=0 tid=0x00007f47240c6800 nid=0x3793 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread2" #7 daemon prio=9 os_prio=0 tid=0x00007f47240c4000 nid=0x3792 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread1" #6 daemon prio=9 os_prio=0 tid=0x00007f47240c2800 nid=0x3791 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" #5 daemon prio=9 os_prio=0 tid=0x00007f47240bf800 nid=0x3790 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" #4 daemon prio=9 os_prio=0 tid=0x00007f47240be000 nid=0x378f waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" #3 daemon prio=8 os_prio=0 tid=0x00007f472408c000 nid=0x378e in Object.wait() [0x00007f46e98c5000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x000000076cf88ee0> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
    - locked <0x000000076cf88ee0> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

"Reference Handler" #2 daemon prio=10 os_prio=0 tid=0x00007f4724087800 nid=0x378d in Object.wait() [0x00007f46e99c6000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x000000076cf86b50> (a java.lang.ref.Reference$Lock)
    at java.lang.Object.wait(Object.java:502)
    at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
    - locked <0x000000076cf86b50> (a java.lang.ref.Reference$Lock)
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

"VM Thread" os_prio=0 tid=0x00007f4724080000 nid=0x378c runnable 

"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00007f472401f000 nid=0x3784 runnable 

"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00007f4724021000 nid=0x3785 runnable 

"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00007f4724022800 nid=0x3786 runnable 

"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00007f4724024800 nid=0x3787 runnable 

"GC task thread#4 (ParallelGC)" os_prio=0 tid=0x00007f4724026000 nid=0x3788 runnable 

"GC task thread#5 (ParallelGC)" os_prio=0 tid=0x00007f4724028000 nid=0x3789 runnable 

"GC task thread#6 (ParallelGC)" os_prio=0 tid=0x00007f4724029800 nid=0x378a runnable 

"GC task thread#7 (ParallelGC)" os_prio=0 tid=0x00007f472402b800 nid=0x378b runnable 

"VM Periodic Task Thread" os_prio=0 tid=0x00007f47240cc800 nid=0x3795 waiting on condition 

JNI global references: 16


Found one Java-level deadlock:
=============================
"Thread-1":
  waiting to lock monitor 0x00007f46dc003f08 (object 0x000000076d0583a0, a com.anantha.algorithms.ThreadJoin$Friend),
  which is held by "Thread-0"
"Thread-0":
  waiting to lock monitor 0x00007f46dc006008 (object 0x000000076d0583e0, a com.anantha.algorithms.ThreadJoin$Friend),
  which is held by "Thread-1"

Java stack information for the threads listed above:
===================================================
"Thread-1":
    at com.anantha.algorithms.ThreadJoin$Friend.bowBack(ThreadJoin.java:102)
    - waiting to lock <0x000000076d0583a0> (a com.anantha.algorithms.ThreadJoin$Friend)
    at com.anantha.algorithms.ThreadJoin$Friend.bow(ThreadJoin.java:92)
    - locked <0x000000076d0583e0> (a com.anantha.algorithms.ThreadJoin$Friend)
    at com.anantha.algorithms.ThreadJoin$2.run(ThreadJoin.java:141)
    at java.lang.Thread.run(Thread.java:745)
"Thread-0":
    at com.anantha.algorithms.ThreadJoin$Friend.bowBack(ThreadJoin.java:102)
    - waiting to lock <0x000000076d0583e0> (a com.anantha.algorithms.ThreadJoin$Friend)
    at com.anantha.algorithms.ThreadJoin$Friend.bow(ThreadJoin.java:92)
    - locked <0x000000076d0583a0> (a com.anantha.algorithms.ThreadJoin$Friend)
    at com.anantha.algorithms.ThreadJoin$1.run(ThreadJoin.java:134)
    at java.lang.Thread.run(Thread.java:745)

Found 1 deadlock.

Heap
 PSYoungGen      total 74752K, used 9032K [0x000000076cf80000, 0x0000000772280000, 0x00000007c0000000)
  eden space 64512K, 14% used [0x000000076cf80000,0x000000076d8520e8,0x0000000770e80000)
  from space 10240K, 0% used [0x0000000771880000,0x0000000771880000,0x0000000772280000)
  to   space 10240K, 0% used [0x0000000770e80000,0x0000000770e80000,0x0000000771880000)
 ParOldGen       total 171008K, used 0K [0x00000006c6e00000, 0x00000006d1500000, 0x000000076cf80000)
  object space 171008K, 0% used [0x00000006c6e00000,0x00000006c6e00000,0x00000006d1500000)
 Metaspace       used 3183K, capacity 4500K, committed 4864K, reserved 1056768K
  class space    used 352K, capacity 388K, committed 512K, reserved 1048576K

1

Aqui está um impasse simples em Java. Precisamos de dois recursos para demonstrar o impasse. No exemplo abaixo, um recurso é o bloqueio de classe (via método de sincronização) e o outro é um inteiro 'i'

public class DeadLock {

    static int i;
    static int k;

    public static synchronized void m1(){
        System.out.println(Thread.currentThread().getName()+" executing m1. Value of i="+i);

        if(k>0){i++;}

        while(i==0){
            System.out.println(Thread.currentThread().getName()+" waiting in m1 for i to be > 0. Value of i="+i);
            try { Thread.sleep(10000);} catch (InterruptedException e) { e.printStackTrace(); }
        }
    }

    public static void main(String[] args) {

        Thread t1 = new Thread("t1") {
            public void run() {
                m1();
            }
        };

        Thread t2 = new Thread("t2") {
            public void run() {
                try { Thread.sleep(100);} catch (InterruptedException e) { e.printStackTrace(); }
                k++;
                m1();
            }
        };

        t1.start();
        t2.start();
    }
}

1
public class DeadLock {

    public static void main(String[] args) {
        Object resource1 = new Object();
        Object resource2 = new Object();
        SharedObject s = new SharedObject(resource1, resource2);
        TestThread11 t1 = new TestThread11(s);
        TestThread22 t2 = new TestThread22(s);
        t1.start();
        t2.start();
    }

}

class SharedObject {
    Object o1, o2;
    SharedObject(Object o1, Object o2) {
        this.o1 = o1;
        this.o2 = o2;
    }
    void m1() {
        synchronized(o1) {
            System.out.println("locked on o1 from m1()");
            synchronized(o2) { 
                System.out.println("locked on o2 from m1()");
            }
        }
    }
    void m2() {
        synchronized(o2) {
            System.out.println("locked on o2 from m2()");
            synchronized(o1) { 
                System.out.println("locked on o1 from m2()");
            }
        }
    }
}

class TestThread11 extends Thread {
    SharedObject s;
    TestThread11(SharedObject s) {
        this.s = s;
    }
    public void run() {
        s.m1();
    }
}

class TestThread22 extends Thread {
    SharedObject s;
    TestThread22(SharedObject s) {
        this.s = s;
    }
    public void run() {
        s.m2();
    }
}

1
Você poderia adicionar algum texto para explicar sua resposta, por favor.
Kmeixner

1

Aqui está um impasse simples em C #.

void UpdateLabel(string text) {
   lock(this) {
      if(MyLabel.InvokeNeeded) {
        IAsyncResult res =  MyLable.BeginInvoke(delegate() {
             MyLable.Text = text;
            });
         MyLabel.EndInvoke(res);
        } else {
             MyLable.Text = text;
        }
    }
}

Se, um dia, você chamar isso do encadeamento da GUI e outro encadeamento também o chamar - você pode travar. O outro encadeamento chega a EndInvoke, espera que o encadeamento da GUI execute o delegado enquanto mantém o bloqueio. O thread da GUI bloqueia no mesmo bloqueio esperando que o outro thread o libere - o que não acontecerá porque o thread da GUI nunca estará disponível para executar o delegado que o outro thread está esperando. (é claro que o bloqueio aqui não é estritamente necessário - nem o EndInvoke, mas em um cenário um pouco mais complexo, um bloqueio pode ser adquirido pelo chamador por outros motivos, resultando no mesmo impasse.)


0
package test.concurrent;
public class DeadLockTest {
   private static long sleepMillis;
   private final Object lock1 = new Object();
   private final Object lock2 = new Object();

   public static void main(String[] args) {
       sleepMillis = Long.parseLong(args[0]);
       DeadLockTest test = new DeadLockTest();
       test.doTest();
   }

   private void doTest() {
       Thread t1 = new Thread(new Runnable() {
           public void run() {
               lock12();
           }
       });
       Thread t2 = new Thread(new Runnable() {
           public void run() {
               lock21();
           }
       });
       t1.start();
       t2.start();
   }

   private void lock12() {
       synchronized (lock1) {
           sleep();
           synchronized (lock2) {
               sleep();
           }
       }
   }

   private void lock21() {
       synchronized (lock2) {
           sleep();
           synchronized (lock1) {
               sleep();
           }
       }
   }

   private void sleep() {
       try {
           Thread.sleep(sleepMillis);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
   }
}
To run the deadlock test with sleep time 1 millisecond:
java -cp . test.concurrent.DeadLockTest 1

0
public class DeadlockProg {

    /**
     * @Gowtham Chitimi Reddy IIT(BHU);
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        final Object ob1 = new Object();
        final Object ob2 = new Object();
        Thread t1 = new Thread(){
            public void run(){
                synchronized(ob1){
                    try{
                        Thread.sleep(100);
                    }
                    catch(InterruptedException e){
                        System.out.println("Error catched");
                    }
                    synchronized(ob2){

                    }
                }

            }
        };
        Thread t2 = new Thread(){
            public void run(){
                synchronized(ob2){
                    try{
                        Thread.sleep(100);
                    }
                    catch(InterruptedException e){
                        System.out.println("Error catched");
                    }
                    synchronized(ob1){                      
                    }
                }               
            }
        };
        t1.start();
        t2.start();
    }

}

0
package ForkBlur;

public class DeadLockTest {
  public static void main(String args[]) {

    final DeadLockTest t1 = new DeadLockTest();
    final DeadLockTest t2 = new DeadLockTest();

    Runnable r1 = new Runnable() {

        @Override
        public void run() {
            try {

                synchronized (t1) {
                    System.out
                            .println("r1 has locked t1, now going to sleep");
                    Thread.sleep(100);
                    System.out
                            .println("r1 has awake , now going to aquire lock for t2");
                    synchronized (t2) {
                        Thread.sleep(100);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    };

    Runnable r2 = new Runnable() {

        @Override
        public void run() {
            try {

                synchronized (t2) {
                    System.out
                            .println("r2 has aquire the lock of t2 now going to sleep");
                    Thread.sleep(100);
                    System.out
                            .println("r2 is awake , now going to aquire the lock from t1");
                    synchronized (t1) {
                        Thread.sleep(100);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    };

    new Thread(r1).start();
    new Thread(r2).start();
  }
}

0

Eu criei um exemplo de DeadLock de trabalho ultra simples: -

package com.thread.deadlock;

public class ThreadDeadLockClient {

    public static void main(String[] args) {
        ThreadDeadLockObject1 threadDeadLockA = new ThreadDeadLockObject1("threadDeadLockA");
        ThreadDeadLockObject2 threadDeadLockB = new ThreadDeadLockObject2("threadDeadLockB");

        new Thread(new Runnable() {

            @Override
            public void run() {
                threadDeadLockA.methodA(threadDeadLockB);

            }
        }).start();

        new Thread(new Runnable() {

            @Override
            public void run() {
                threadDeadLockB.methodB(threadDeadLockA);

            }
        }).start();
    }
}

package com.thread.deadlock;

public class ThreadDeadLockObject1 {

    private String name;

    ThreadDeadLockObject1(String name){
        this.name = name;
    }

    public  synchronized void methodA(ThreadDeadLockObject2 threadDeadLockObject2) {
        System.out.println("In MethodA "+" Current Object--> "+this.getName()+" Object passed as parameter--> "+threadDeadLockObject2.getName());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        threadDeadLockObject2.methodB(this);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }   
}

package com.thread.deadlock;

public class ThreadDeadLockObject2 {

    private String name;

    ThreadDeadLockObject2(String name){
        this.name = name;
    }

    public  synchronized void methodB(ThreadDeadLockObject1 threadDeadLockObject1) {
        System.out.println("In MethodB "+" Current Object--> "+this.getName()+" Object passed as parameter--> "+threadDeadLockObject1.getName());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        threadDeadLockObject1.methodA(this);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

No exemplo acima, 2 threads estão executando os métodos sincronizados de dois objetos diferentes. O método sincronizadoA é chamado pelo objeto threadDeadLockA e o método sincronizado B é chamado pelo objeto threadDeadLockB. No métodoA, uma referência de threadDeadLockB é passada e no métodoB uma referência de threadDeadLockA é passada. Agora, cada thread tenta travar o outro objeto. No métodoA, o encadeamento que está bloqueando o threadDeadLockA está tentando obter o bloqueio do objeto threadDeadLockB e, da mesma forma, no métodoB, o segmento que está bloqueando o threadDeadLockB está tentando obter o bloqueio do threadDeadLockA. Assim, ambos os threads aguardarão para sempre criando um deadlock.


0

Deixe-me explicar mais claramente usando um exemplo com mais de 2 threads.

Digamos que você tenha n threads, cada um segurando os bloqueios L1, L2, ..., Ln respectivamente. Agora, digamos que, a partir do thread 1, cada thread tenta adquirir o bloqueio de seu thread vizinho. Portanto, o thread 1 é bloqueado para tentar adquirir L2 (como L2 é propriedade do thread 2), o thread 2 é bloqueado para L3 e assim por diante. O thread n é bloqueado para L1. Isso agora é um deadlock, pois nenhum thread é capaz de executar.

class ImportantWork{
   synchronized void callAnother(){     
   }
   synchronized void call(ImportantWork work) throws InterruptedException{
     Thread.sleep(100);
     work.callAnother();
   }
}
class Task implements Runnable{
  ImportantWork myWork, otherWork;
  public void run(){
    try {
      myWork.call(otherWork);
    } catch (InterruptedException e) {      
    }
  }
}
class DeadlockTest{
  public static void main(String args[]){
    ImportantWork work1=new ImportantWork();
    ImportantWork work2=new ImportantWork();
    ImportantWork work3=new ImportantWork();
    Task task1=new Task(); 
    task1.myWork=work1;
    task1.otherWork=work2;

    Task task2=new Task(); 
    task2.myWork=work2;
    task2.otherWork=work3;

    Task task3=new Task(); 
    task3.myWork=work3;
    task3.otherWork=work1;

    new Thread(task1).start();
    new Thread(task2).start();
    new Thread(task3).start();
  }
}

No exemplo acima, você pode ver que há três threads segurando Runnabletask1, task2 e task3. Antes da instrução, sleep(100)os threads adquirem os três bloqueios dos objetos de trabalho ao entrarem no call()método (devido à presença de synchronized). Mas assim que eles tentam callAnother()no objeto do thread vizinho, eles são bloqueados, levando a um deadlock, porque os bloqueios desses objetos já foram tomados.


0
CountDownLatch countDownLatch = new CountDownLatch(1);
ExecutorService executorService = ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(() -> {
    Future<?> future = executorService.submit(() -> {
        System.out.println("generated task");
    });
    countDownLatch.countDown();
    try {
        future.get();
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
         e.printStackTrace();
    }
});


countDownLatch.await();
executorService.shutdown();

0

Uma maneira sorrateira de entrar em conflito com apenas um único thread é tentar bloquear o mesmo mutex (não recursivo) duas vezes. Este pode não ser o exemplo simples que você estava procurando, mas com certeza eu já encontrei esses casos.

#include <mutex>
#include <iostream>

int main()
{
  std::mutex m;
  m.lock();
  m.lock();
  std::cout << "Expect never to get here because of a deadlock!";
}

0

Aqui está meu exemplo detalhado de impasse , depois de passar muito tempo. Espero que ajude :)

package deadlock;

public class DeadlockApp {

    String s1 = "hello";
    String s2 = "world";

    Thread th1 = new Thread() {
        public void run() {
            System.out.println("Thread th1 has started");
            synchronized (s1) { //A lock is created internally (holds access of s1), lock will be released or unlocked for s1, only when it exits the block Line #23
                System.out.println("Executing first synchronized block of th1!");
                try {
                    Thread.sleep(1000);
                } catch(InterruptedException ex) {
                    System.out.println("Exception is caught in th1");
                }
                System.out.println("Waiting for the lock to be released from parrallel thread th1");
                synchronized (s2) { //As another has runned parallely Line #32, lock has been created for s2
                    System.out.println(s1 + s2);
                }

            }
            System.out.println("Thread th1 has executed");
        }
    };


    Thread th2 = new Thread() {
        public void run() {
            System.out.println("Thread th2 has started");
            synchronized (s2) { //A lock is created internally (holds access of s2), lock will be released or unlocked for s2, only when it exits the block Line #44
                System.out.println("Executing first synchronized block of th2!");
                try {
                    Thread.sleep(1000);
                } catch(InterruptedException ex) {
                    System.out.println("Exception is caught in th2");
                }
                System.out.println("Waiting for the lock to be released from parrallel thread th2");
                synchronized (s1) { //As another has runned parallely Line #11, lock has been created for s1
                    System.out.println(s1 + s2);
                }

            }
            System.out.println("Thread th2 has executed");
        }
    };

    public static void main(String[] args) {
        DeadlockApp deadLock = new DeadlockApp();
        deadLock.th1.start();
        deadLock.th2.start();
        //Line #51 and #52 runs parallely on executing the program, a lock is created inside synchronized method
        //A lock is nothing but, something like a blocker or wall, which holds access of the variable from being used by others.
        //Locked object is accessible, only when it is unlocked (i.e exiting  the synchronized block)
        //Lock cannot be created for primitive types (ex: int, float, double)
        //Dont forget to add thread.sleep(time) because if not added, then object access will not be at same time for both threads to create Deadlock (not actual runtime with lots of threads) 
        //This is a simple program, so we added sleep90 to create Deadlock, it will execute successfully, if it is removed. 
    }

    //Happy coding -- Parthasarathy S
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.