2012-04-11 10 views
0

Ich teste einen Java-Multi-Threading-Beispielcode, aber der in der for-Schleife von qB.start() gestartete Thread ist blockiert, weil er auf die Eingabe von qB-Monitor wartet. Was ist die Ursache für diese Blockade?So lösen Sie dieses Thread-Blockierungsproblem

Vielen Dank.

import java.util.*; 

class QA { 

public synchronized void open() throws Exception { 

    Thread o = new Thread() { 

     public void run() { 

      QB qB = new QB(); 

      qB.start(); 
     } 
    }; 

    o.start(); 
} 

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

    new QA().open(); 
} 

public class QB { 

private boolean shutdown; 
private Vector<Thread> tList; 
private final Object waitingLock = new Object(); 

public QB() { 

    tList = new Vector<Thread>(); 
} 

public synchronized void start() { 


    for(int i = 0; i < 1; i++) { 

     final int id = i; 

     Thread t = new Thread("Thread " + id) { 

      public void run() { 

       load(id); 
      } 
     }; 

     tList.add(i, t); 

     t.start(); 

    } 

    tMonitor(); 
    waitUntilFinished(); 
} 

private void tMonitor() { 

    Thread cmt = new Thread("T Monitor Thread") { 

     public void run() { 

      synchronized(waitingLock) { 

       while(tList.size() > 0) { 

        try { 

         sleep(10000); 

        } catch(Exception e) { 

         e.printStackTrace(); 
        } 
       } 

       waitingLock.notifyAll(); 
      } 
     } 
    }; 

    cmt.start(); 
} 

private void waitUntilFinished() { 

    synchronized(waitingLock) { 

     while(!isShutDown()) { 

      try { 


       waitingLock.wait(); 


      } catch(Exception e) { 

     e.printStackTrace(); 
      } 
     } 
    } 

} 

private synchronized void load(int id) { 

    try { 

     System.out.println("blocked here"); 

// some work done here 

removeFromTList(id); 


    } catch(Exception e) { 

     e.printStackTrace(); 
    } 
} 


public synchronized boolean isShutDown() { 

    return shutdown; 
} 
} 
} 
+0

Können wir wieder den Code für 'removeFromTList' @john sehen. – Gray

+0

öffentlich synchronisierte void removeFromTList (int pos) { tList.removeElementAt (pos); } – John

+0

Ja, dieser Code hat Probleme. Siehe meine Antwort. – Gray

Antwort

3

Das erste Problem, das ich sehe, ist, dass QB#start() auf die Instanz von QB synchronisiert wird. Innerhalb des Threads t, den Sie versuchen zu spawnen, wird load(id) auch auf derselben Instanz von QB synchronisiert. Also, wenn Sie t.start() die t Thread-Blöcke aufrufen, bis QB#start() beendet.

Vermutlich am Ende des QB#start() Verfahrens wird QB#waitUntilFinished() soll warten alle t Threads zu beenden, aber sie können die QB#load Methode nicht einmal betreten, weil sie immer noch für die QB#start() Methode wartet die zur Freigabe Sperren Sie die Instanz.

Also, kreisförmige Deadlock.

+0

Gute Eins. Ich konzentrierte mich auf die anderen 4 Bugs und fehlenden Code. – Gray

+0

Was ist der beste Weg, den Sie denken, um dieses Problem zu lösen? – John

+0

Folgen Sie der Faustregel, dass Sie so wenig wie möglich innerhalb von "Synchronisieren" -Blöcken tun. In Ihrem Fall könnten Sie also alle 'tList'-Operationen auf' tList' synchronisieren, anstatt 'synchronisierte' Methoden zu verwenden, da' tList' Ihre einzige gemeinsame Ressource ist. – trutheality

1

Edit:

Ok, jetzt, wo wir sehen, wie die Fäden aus tList der Bug entfernt werden vollständig offenbart.

Wenn der Index 0 Thread zuerst beendet wird, wird es sich selbst aus der Liste entfernen. Das heißt, wenn der Index 1-Thread beendet ist, wird die 1. Position von Vector entfernt, aber das zeigt nicht mehr auf sich selbst. Es entfernt den # 2-Thread. Früher oder später werden Sie eine Ausnahme erhalten, wenn das Entfernen passiert, weil es einen ungültigen Index entfernen wird.

Sie müssen Elemente aus den Vector nach Adressen und nicht von Position entfernen:

tList.remove(this); 

Das wird den aktuellen Thread aus der Liste entfernen. Sie sollten auch nur ein add(t) tun, anstatt eine add(i t) in der Startschleife:

tList.add(t); 

Sie jetzt brauchen nicht die ID Position in Ihrem Thread übergeben überhaupt.


Ich sehe nicht, wo Sie die fertigen Fäden aus Ihrem tList entfernen sind. Ich sehe eine Definition (nicht, dass Sie Ihr OP bearbeitet haben) einer removeFromTList() Methode, aber ich sehe es nirgends verwendet. In tMonitor sind Sie in einer while-Schleife hier:

 while(tList.size() > 0) { 
      try { 
       sleep(10000); 
      } catch(Exception e) { 
       e.printStackTrace(); 
      } 
     } 
     // you never get to this line 
        waitingLock.notifyAll(); 

Aber ich sehe nichts, das den Faden aus der Liste entfernt. Vielleicht sollten die Fäden, wenn sie fertig sind, sich selbst entfernen?

Wenn tMonitor Faden nie dann aus dieser Schleife wird es nie ruft:

waitingLock.notifyAll(); 

So ist der Haupt-Thread für immer in waitUntilFinished(); hängen wird.

synchronized(waitingLock) { 
    while(!isShutDown()) { 
     try { 
      waitingLock.wait(); 
     } catch(Exception e) { 
      e.printStackTrace(); 
     } 
    } 

Auch Sie wollen nicht ein sleep in tMonitor() zu tun, weil Sie in einem synchronized Block sind. es

waitingLock.wait(10000); 

Nichts wird je benachrichtigen, aber es ist schlechte Form das Schloss wie in einem Schlaf zu halten: Sie sollten eine tun.

+0

Entschuldigung, ich habe den Teil weggelassen. Ich habe den Teil eingefügt, aber das Problem bleibt bestehen. – John

+0

Wo nennst du 'removeFromTlist' @john? – Gray

+0

In Laden (ID) Methode – John