Semplici esempi di deadlock


92

Vorrei spiegare i deadlock del threading ai neofiti. Ho visto molti esempi di deadlock in passato, alcuni usando codice e altri usando illustrazioni (come le famose 4 auto ). Ci sono anche problemi classici facilmente bloccabili come The Dining Philosophers , ma questi potrebbero essere troppo complessi per un vero principiante da afferrare appieno.

Sto cercando il più semplice esempio di codice per illustrare cosa sono i deadlock. L'esempio dovrebbe:

  1. Relazionarsi a uno scenario di programmazione "reale" che abbia un senso
  2. Sii molto breve, semplice e diretto

Che cosa mi consiglia?


perché non usare le famose 4 auto, come mi sembra abbastanza semplice.
vehomzzz

2
Le 4 auto non sono uno scenario di programmazione e non è banale per un principiante astrarre un problema alla forma delle 4 auto. Li uso, ma voglio mostrare uno scenario di programmazione in cui si verifica un deadlock.
Roee Adler

Risposte:


139

Forse una semplice situazione bancaria.

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);
    }

}

Ovviamente, se ci sono due thread che tentano di eseguire il trasferimento ( a, b ) e il trasferimento ( b, a ) allo stesso tempo, si verificherà un deadlock perché cercano di acquisire le risorse in ordine inverso.

Questo codice è ottimo anche per cercare soluzioni al deadlock. Spero che questo ti aiuti!


1
Sarebbe perfetto se tu o qualcun altro poteste dare la soluzione a questo problema.
Jacky

2
@Jacky La soluzione per questo problema è pubblicata da Will Hartung qui: stackoverflow.com/questions/13326861/avoid-deadlock-example/…
Piotr Chojnacki

2
Sono confuso dalla tua sintassi. Cos'è il metodo sync ()? Capirei se sync (from); ... release (from); sono stati sostituiti con sincronizzato (da) {...}
Ellen Spertus

1
@espertus syncpuò essere qualcosa come: sync(Account & a) { a.mutex.lock(); }.
vladon

1
javaworld.com/article/2075692/java-concurrency/… (Brian Goetz) spiega la soluzione a questo problema.
lingareddyk

59

Lascia che la natura spieghi la situazione di stallo,

Deadlock: Frog vs Snake

"Mi sarebbe piaciuto vederli prendere strade separate, ma ero esausto", ha detto il fotografo. "La rana cercava continuamente di strappare il serpente, ma il serpente non voleva lasciarlo andare" .

inserisci qui la descrizione dell'immagine


59
Carino, ma non spiega come si verificano i deadlock in un contesto di programmazione.
jalf

ok jalf, almeno hai giustificato il voto negativo. Comunque, è simile all'esempio "4 macchine". Una rappresentazione carina di come appare una situazione di stallo.
Nick Dandoulakis

@ Nick Dandoulakis: eccellente presentazione pittorica. L'immagine spiega il concetto di deadlock
Rasmi Ranjan Nayak

@ NickDandoulakis - Non è un buon esempio di foto imho. Il codice semplice sarebbe utile qui.
Erran Morad

13
Come dovrebbe essere CARINO? I serpenti e le rane velenosi si stanno mangiando a vicenda ed è spaventoso !!!
vikkyhacks

53

Ecco un esempio di codice del dipartimento di informatica di un'università di Taiwan che mostra un semplice esempio java con blocco delle risorse. È molto importante per me la "vita reale". Codice di seguito:

/**
 * 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
Il problema è che non è davvero un esempio di "vita reale". Si tratta di "risorsa 1" e "risorsa 2", e sarebbe bello collegarlo effettivamente a un problema di programmazione effettivo (intendo, direttamente utilizzabile nella pratica, con riferimento al dominio del problema, ecc.)
Jay

7
Un buon esempio secondo me. Grazie.
James Raitsev

Questo codice sembra essere stato pubblicato in un paio di libri diversi ... stackoverflow.com/a/11338853/112705
Dan J

15

Se method1 () e method2 () verranno entrambi chiamati da due o più thread, c'è una buona possibilità di deadlock perché se il thread 1 acquisisce il blocco sull'oggetto String durante l'esecuzione di method1 () e il thread 2 acquisisce il blocco sull'oggetto Integer durante l'esecuzione di method2 () entrambi aspetteranno l'un l'altro per rilasciare il blocco su Integer e String per procedere oltre, cosa che non accadrà mai.

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");
        }
    }
}

Rapido e semplice. Bello.
user1068352

13

Uno dei semplici esempi di deadlock in cui mi sono imbattuto.

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...");
            }
         }
      }
   }
}

Mi piace quell'esempio. Ma perché la classe SimpleDeadLock esclude da Thread? Non è necessario.
Charmin

1
Questa è praticamente la stessa cosa di questa risposta: stackoverflow.com/a/1385868/1310566 . E cosa private int indexci fa lì?
Simon Forsberg

6

Ecco un semplice esempio in 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

Si prega di vedere la mia risposta a questa domanda . In conclusione, ogni volta che due thread devono acquisire due risorse diverse e lo fanno in ordini diversi, è possibile ottenere deadlock.


2
Non vedo davvero il punto nel duplicare le informazioni da un'altra risposta qui. Presumo che se pensi che questa risposta possa essere migliorata, sei libero di modificarla da solo.
djna

Penso che questa situazione sia chiamata "inversione del blocco". Beh, so che si chiama inversione del blocco, perché io lo chiamo così, ma penso che sia anche il termine artistico per questo :-)
Steve Jessop

4

Un esempio a cui posso pensare è lo scenario da tavolo, torcia elettrica e batterie. Immagina una torcia elettrica e un paio di batterie posizionate sopra un tavolo. Se dovessi camminare fino a questo tavolo e prendere le batterie mentre un'altra persona ha la torcia, entrambi sarete costretti a fissarvi goffamente mentre aspettate chi rimetterà il proprio oggetto sul tavolo. Questo è un esempio di deadlock. Tu e la persona aspettate risorse, ma nessuno di voi rinuncia alla propria risorsa.

Allo stesso modo, in un programma, il deadlock si verifica quando due o più thread (tu e l'altra persona) aspettate che due o più blocchi (torcia e batterie) vengano liberati e le circostanze nel programma sono tali che i blocchi non vengono mai liberati ( entrambi avete un pezzo del puzzle).

Se conosci java, ecco come puoi rappresentare questo 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 esegui questo esempio, noterai che a volte le cose funzionano bene e correttamente. Ma a volte il tuo programma semplicemente non stamperà nulla. Questo perché una persona ha le batterie mentre un'altra ha la torcia che impedisce loro di accendere la torcia causando un deadlock.

Questo esempio è simile all'esempio fornito dai tutorial java: http://docs.oracle.com/javase/tutorial/essential/concurrency/deadlock.html

Un altro esempio è l'esempio del ciclo:

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();
    }
}

Questo esempio può stampare "Non fatto" più e più volte o non può mai stampare "Non fatto". Il primo accade perché il primo thread acquisisce il blocco di classe e non lo rilascia mai, impedendo che il secondo thread acceda a "stopLoop". E l'ultimo accade perché il secondo thread è stato avviato prima del primo thread facendo sì che la variabile 'done' sia vera prima che il primo thread venga eseguito.


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

Considero il problema dei Filosofi Pranzanti come uno degli esempi più semplici nel mostrare i deadlock, poiché i 4 requisiti del deadlock possono essere facilmente illustrati dal disegno (specialmente l'attesa circolare).

Considero gli esempi del mondo reale molto più confusi per il principiante, anche se in questo momento non riesco a pensare a un buon scenario del mondo reale (sono relativamente inesperto con la concorrenza del mondo reale).


3

Recentemente mi sono reso conto che le liti tra coppie non sono altro che un punto morto .. dove di solito uno dei processi deve bloccarsi per risolverlo, ovviamente è la priorità minore (Ragazzo;)).

Ecco l'analogia ...

Processo1: Ragazza (G) Processo2: Ragazzo (B) Risorsa1: Scusa Risorsa2:
Accettare il proprio errore

Condizioni necessarie:
1. Esclusione reciproca: solo uno tra G o B può chiedere scusa o accettare il proprio errore alla volta.
2. Hold and Wait: in un momento, uno sta tenendo Scusa e l'altro Accetta il proprio errore, uno sta aspettando che Accetta il proprio errore per rilasciare scusa, e l'altro sta aspettando che scusi per rilasciare accettando il proprio errore.
3. Nessuna prelazione: nemmeno Dio può costringere B o G a rilasciare Mi dispiace o Accetto il proprio errore. E volontariamente? Ma stai scherzando??
4. Attesa circolare: ancora una volta, chi si dispiace aspetta che l'altro accetti i propri errori, e chi tiene accetta i propri errori vuole che gli altri chiedano scusa prima. Quindi è circolare.

Quindi i deadlock si verificano quando tutte queste condizioni sono attive allo stesso tempo, e questo è sempre il caso in un combattimento di coppia;)

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


3

Un altro esempio di deadlock semplice con due risorse diverse e due thread in attesa di rilascio reciproco della risorsa. Direttamente da 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.Possiamo fare questo esempio di guaranteedeadlock?
Erran Morad

Questo è lo stesso codice postato da Kyle , perché aggiungere una risposta duplicata tre anni dopo un'altra risposta? (e perché lo commento, altri tre anni dopo?)
Simon Forsberg,

2

Lo stallo può verificarsi in una situazione in cui a Girl1vuole flirtare con Guy2, che viene catturato da un altro Girl2e Girl2vuole flirtare con un Guy1che viene catturato Girl1. Poiché entrambe le ragazze stanno aspettando di scaricarsi a vicenda, la condizione è chiamata deadlock.

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

Il problema dei produttori-consumatori insieme al problema dei filosofi della ristorazione è probabilmente tanto semplice quanto sta per diventare. Ha anche uno pseudocodice che lo illustra. Se sono troppo complessi per un principiante, è meglio che si sforzino di capirli.


1

Scegli il possibile scenario semplicistico in cui può verificarsi un deadlock quando si presenta il concetto ai tuoi studenti. Ciò comporterebbe un minimo di due thread e un minimo di due risorse (credo). L'obiettivo è progettare uno scenario in cui il primo thread ha un blocco sulla risorsa uno e sta aspettando che il blocco sulla risorsa due venga rilasciato, mentre allo stesso tempo il thread due mantiene un blocco sulla risorsa due e sta aspettando il blocco sulla risorsa uno da rilasciare.

Non importa veramente quali siano le risorse sottostanti; per semplicità, potresti semplicemente renderli un paio di file in cui entrambi i thread sono in grado di scrivere.

EDIT: questo presuppone che non ci siano comunicazioni tra processi diversi dai blocchi mantenuti.


1

Ho scoperto che un po 'difficile da capire leggendo il problema dei filosofi a tavola, il deadlock IMHO è in realtà correlato all'allocazione delle risorse. Vorrei condividere un esempio più semplice in cui 2 infermiere devono lottare per 3 attrezzature per completare un'attività. Sebbene sia scritto in java. Viene creato un semplice metodo lock () per simulare come si verifica il deadlock, in modo che possa essere applicato anche in altri linguaggi di programmazione. http://www.justexample.com/wp/example-of-deadlock/


1

Semplice esempio da 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();
}

}

Produzione:

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 

Dump del filo:

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

Ecco un semplice deadlock in Java. Abbiamo bisogno di due risorse per dimostrare la situazione di stallo. Nell'esempio seguente, una risorsa è il blocco di classe (tramite il metodo di sincronizzazione) e l'altra è un numero intero '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
Potresti aggiungere del testo per spiegare la tua risposta, per favore.
Kmeixner

1

Ecco un semplice deadlock in 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, un giorno, lo chiami dal thread della GUI e anche un altro thread lo chiama, potresti bloccarsi. L'altro thread arriva a EndInvoke, attende che il thread della GUI esegua il delegato mantenendo il blocco. Il thread della GUI si blocca sullo stesso blocco in attesa che l'altro thread lo rilasci, cosa che non lo farà perché il thread della GUI non sarà mai disponibile per eseguire il delegato che l'altro thread sta aspettando. (Ovviamente il blocco qui non è strettamente necessario, né forse lo è EndInvoke, ma in uno scenario leggermente più complesso, un blocco potrebbe essere acquisito dal chiamante per altri motivi, risultando nello stesso deadlock.)


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

Ho creato un esempio di DeadLock funzionante ultra semplice: -

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;
    }
}

Nell'esempio precedente 2 thread stanno eseguendo i metodi sincronizzati di due oggetti diversi. Il metodo A sincronizzato viene chiamato dall'oggetto threadDeadLockA e il metodo B sincronizzato viene chiamato dall'oggetto threadDeadLockB. In methodA viene passato un riferimento a threadDeadLockB e in methodB viene passato un riferimento a threadDeadLockA. Ora ogni thread cerca di ottenere il blocco su un altro oggetto. In methodA il thread che tiene un blocco su threadDeadLockA sta cercando di ottenere il blocco sull'oggetto threadDeadLockB e analogamente in methodB il thread che sta mantenendo un blocco su threadDeadLockB sta cercando di ottenere il blocco su threadDeadLockA. Quindi entrambi i thread aspetteranno per sempre creando un deadlock.


0

Lascia che ti spieghi più chiaramente usando un esempio con più di 2 thread.

Supponiamo di avere n thread ciascuno con i lock L1, L2, ..., Ln rispettivamente. Supponiamo ora, a partire dal thread 1, che ogni thread cerchi di acquisire il lock del thread vicino. Quindi, il thread 1 viene bloccato per aver tentato di acquisire L2 (poiché L2 è di proprietà del thread 2), il thread 2 viene bloccato per L3 e così via. Il thread n viene bloccato per L1. Questo è ora un deadlock poiché nessun thread è in grado di eseguire.

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();
  }
}

Nell'esempio sopra, puoi vedere che ci sono tre thread che contengono Runnables task1, task2 e task3. Prima dell'istruzione sleep(100)i thread acquisiscono i blocchi dei tre oggetti di lavoro quando entrano nel call()metodo (per la presenza di synchronized). Ma non appena ci provanocallAnother() l'oggetto del thread vicino, vengono bloccati, causando un deadlock, perché i blocchi di quegli oggetti sono già stati presi.


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

Un modo subdolo per deadlock con un solo thread è provare a bloccare lo stesso mutex (non ricorsivo) due volte. Questo potrebbe non essere il semplice esempio che stavi cercando, ma sicuramente ho già riscontrato casi del genere.

#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

Ecco il mio esempio dettagliato di deadlock , dopo aver trascorso molto tempo. Spero che sia d'aiuto :)

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
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.