2016-09-07 1 views
0

Für meine Programmiersprachen-Klasse haben wir ein einfaches Java-Deadlock-Beispiel gegeben und werden gebeten, es zu lösen. Ich möchte nicht direkt die Antwort auf dieses Problem, ich möchte hauptsächlich wissen, wo mein Verständnis fehlt. Hier ist der Code:Bitte helfen Sie mir, dieses Deadlock-Beispiel zu verstehen

import java.applet.*; 
import javax.swing.*; 
import java.awt.*; 
import java.awt.event.*; 

// Attempt at a simple handshake. Girl pings Boy, gets confirmation. 
// Then Boy pings girl, get confirmation. 
class Monitor { 
    String name; 

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

    public String getName() { return this.name; } 

    // Girl thread invokes ping, asks Boy to confirm. But Boy invokes ping, 
    // and asks Girl to confirm. Neither Boy nor Girl can give time to their 
    // confirm call because they are stuck in ping. Hence the handshake 
    // cannot be completed. 
    public synchronized void ping (Monitor p) { 
     System.out.println(this.name + " (ping): pinging " + p.getName()); 
     p.confirm(this); 
     System.out.println(this.name + " (ping): got confirmation"); 
    } 

    public synchronized void confirm (Monitor p) { 
     System.out.println(this.name+" (confirm): confirm to "+p.getName()); 
    } 
} 

class Runner extends Thread { 
    Monitor m1, m2; 

    public Runner (Monitor m1, Monitor m2) { 
     this.m1 = m1; 
     this.m2 = m2; 
    } 

    public void run() { 
     //System.out.println(m1.getName() + " about to ping " + m2.getName()); 
     m1.ping(m2); 
    } 
} 

public class DeadLock { 
    public static void main (String args[]) { 
     int i=1; 
     System.out.println("Starting..."+(i++)); 
     Monitor a = new Monitor("Girl"); 
     Monitor b = new Monitor("Boy"); 
     (new Runner(a, b)).start(); 
     (new Runner(b, a)).start(); 
    } 
} 

Wenn ich führen Sie den obigen Code Ich glaube, die folgende jedes Mal passieren sollte (obwohl es nicht der Fall ist, denn manchmal Deadlock wir):

Mädchen Pings Boy, eine Sperre setzen auf die ping() Methode. Mädchen, innerhalb ping(), versucht, boy.confirm() anzurufen. Boy's confirm() Antworten, so bringt uns zurück zu Girl.ping(), wo es endet, nimmt die Sperre von ping(), und Boy Instanz genau das gleiche. Mit all den Sperren scheint es, dass das gesamte Programm serialisiert ist und somit den Zweck des Multithreading vereitelt. Egal, erhalte ich normalerweise die folgende Ausgabe

Starting...1 
Girl (ping): pinging Boy 
Boy (confirm): confirm to Girl 
Girl (ping): got confirmation 
Boy (ping): pinging Girl 
Girl (confirm): confirm to Boy 
Boy (ping): got confirmation 

aber manchmal bekommen wir eine Sackgasse und der Ausgang wird:

Girl (ping): pinging Boy 
Boy (ping): pinging Girl 

Ich verstehe nicht, wie wir, obwohl in diesem Zustand bekommen, da es scheint Wir verriegeln die ping() Methode, wenn wir zum ersten Mal reingehen, also wie könnte Boy ping() anrufen, wenn das Mädchen es bereits benutzt? Versucht Mädchen, boy.confirm() anzurufen, wenn Boy beschäftigt ist, ping() zu rufen?

+0

Ihr Ziel ist, dass Ihr Programm serialisierbar ist. Es verhindert nicht den Zweck des Multithreading. Wenn Sie eine Ressource und mehr als einen Thread haben, kann keine Magie erzeugt werden, dh mehrere Threads können die Ressource nicht gleichzeitig verwenden. – UmNyobe

Antwort

5

Ihre ping Methode synchronisiert und nimmt die Sperre auf this, dann geht es confirm auf p zu nennen, damit seine Sperre versuchen, auch zu nehmen. In den Schritten:

  1. "Mädchen" thread erwirbt Sperre auf Boy Objekt tritt ping;
  2. "Boy" Thread erwirbt Sperre auf Girl Objekt, tritt ping;
  3. Mädchen möchte anrufen , wartet auf das Schloss;
  4. Junge möchte Girl.confirm anrufen, wartet auf das Schloss;
  5. Deadlock.
+0

Was mir nicht klar war, war, dass wir eine Sperre für eine andere Instanz erworben haben. Vielen Dank. –

0
  • Gewinde 1:
  • Thread 1 starten: Aufruf ping auf a, den Monitor auf einem erhalten, führen System.out.println Girl (ping) zu drucken: Pingen Boy
  • Gewinde 1: preempted von dem VM
  • Thread 2: start
  • Thread 2: Aufruf ping auf b, erhalten den Monitor auf b, führen System.out.println drucken Boy (ping): Pingen Mädchen
  • Thread 2: rufen a.confirm, warten auf dem Monitor auf einem.
  • Gewinde 1: Lebenslauf
  • Thema 1: b.confirm, wartet auf dem Monitor auf b
  • Thread 1 und 2 warten nun auf den Ressourcen den anderen Thread ist Halt nennen. Deadlock

Die Sache hier ist, dass public synchronized void ping (Monitor p) bedeutet einen Monitor auf der Instanz der Klasse. Zwei verschiedene Instanzen werden in kritischen Abschnitten völlig unabhängig voneinander sein.

Ein Deadlock tritt häufig auf, wenn Synchronisationsmechanismen in unterschiedlichen Reihenfolgen von verschiedenen Threads erfasst werden.Um dieses Problem zu lösen (im Rahmen der Übung) gibt es zwei Möglichkeiten: Formulieren der Synchronisation um

  1. Synchronisieren auf der Klasseninstanz, die

    public void ping (Monitor p) { 
        synchronized(Monitor.class) { 
    
        } 
    } 
    
  2. Radikal ist, das ist ausführlich und/oder fehleranfällig. Zum Beispiel

    class Runner extends Thread { 
        Monitor m1, m2; 
        bool m1_first; 
        public Runner (Monitor m1, Monitor m2, bool sync_m1_first) { 
         this.m1 = m1; 
         this.m1 = m2; 
         m1_first = sync_m1_first; 
        } 
    
        public void run() { 
    
         if(m1_first) 
         { 
          synchronized(m1) { 
           synchronized(m2) { 
            m1.ping(m2); 
           } 
          } 
         } 
         else 
         { 
          synchronized(m2) { 
           synchronized(m1) { 
            m1.ping(m2); 
           } 
          } 
         } 
        } 
    } 
    ... 
    (new Runner(a, b, true)).start(); 
    (new Runner(b, a, false)).start(); 
    
Verwandte Themen