2012-04-11 2 views
0

Я тестирую пример многопоточного кода Java, но поток, запущенный в цикле for qB.start(), заблокирован, потому что он ждет ввода qB-монитора. В чем причина этой блокировки?Как решить эту проблему с блокировкой потоков

спасибо.

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

Можем ли мы снова увидеть код для 'removeFromTList' @john. – Gray

+0

public synchronized void removeFromTList (int pos) { tList.removeElementAt (pos); } – John

+0

Да, этот код имеет проблемы. См. Мой ответ. – Gray

ответ

3

Первая проблема, которую я вижу, заключается в том, что QB#start() синхронизирован на примере QB. Внутри нити t, которую вы пытаетесь создать, load(id) также синхронизируется в том же экземпляре QB. Поэтому, когда вы вызываете t.start()t, блокировочные блоки до QB#start() заканчивается.

Предположительно, в конце метода QB#start(), QB#waitUntilFinished() должен ждать все t нити, чтобы закончить, но они не могут даже войти в метод QB#load, потому что они все еще ждут метода QB#start(), чтобы освободить блокировка на примере QB.

Итак, круговой тупик.

+0

Хорошо. Я сосредоточился на других 4 ошибках и недостающем коде. – Gray

+0

Как вы думаете, что я могу использовать для решения этой проблемы? – John

+0

Следуйте за эмпирическим правилом как можно меньше внутри блоков 'synchronizes'. Таким образом, в вашем случае вы можете синхронизировать все операции 'tList' с' tList' вместо использования 'synchronized'-методов, так как' tList' - ваш единственный общий ресурс. – trutheality

1

Edit:

Хорошо, теперь, когда мы видим, как нити удаляются из tList ошибка будет полностью раскрыта.

Если поток индекса 0 заканчивается первым, он удаляется из списка. Это означает, что когда поток индекса 1 заканчивается, он удалит 1-ю позицию из Vector, но это больше не указывает на себя. Он удаляет поток # 2. Рано или поздно вы получите исключение, когда удаление произойдет, потому что он собирается удалить недопустимый индекс.

Вы должны удалить элементы из Vector по адресу, а не по позиции:

tList.remove(this); 

Это удалит текущий поток из списка. Вы должны также вобще add(t) вместо add(i t) в цикле запуска:

tList.add(t); 

Теперь не нужно идентификатор позиции переходила в ваш поток на всех.


Я не вижу, где вы удаляете законченные темы с вашего tList. Я вижу определение (не то, что вы отредактировали ваш OP) метода removeFromTList(), но я не вижу его в любом месте. В tMonitor вы находитесь в цикле, а здесь:

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

Но я не вижу ничего, что удаляет нить из списка. Может быть, когда каждая нить заканчивается, они должны удалить себя?

Если tMonitor поток никогда не выходит из этого цикла, то он никогда не называет:

waitingLock.notifyAll(); 

Таким образом, основная нить будет висеть вечно в waitUntilFinished();.

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

Кроме того, вы не хотите, чтобы сделать sleep в tMonitor(), потому что вы в synchronized блоке. Вы должны делать:

waitingLock.wait(10000); 

Ничего не сообщит об этом, но это плохая форма, чтобы держать замок таким образом во сне.

+0

Извините, что я оставил эту часть, я включил часть, но проблема все еще остается. – John

+0

Где вы называете 'removeFromTlist' @john? – Gray

+0

Метод load (id) – John