2013-03-21 59 views
0

我目前正在編寫一個包含一堆按鈕的Swing接口的小應用程序。現在我的問題如下:啓動應用程序後,調用一個方法,我想等待兩個按鈕被按下,然後正常進行。我有兩個線程,一個是主線程,另一個是爲了等待兩個按鈕被按下而創建的。對於按鈕,我像往常一樣添加了一個ActionListener,它將變量加1,並調用一個方法,當變量爲2時喚醒另一個。
因此,這裏是我的代碼:Java中的多線程:等到兩個按鈕被按下?

int counter = 0; 
static Thread thread1; 
static Thread thread2; 

public static void main(String[] args) { 
    EventQueue.invokeLater(new Runnable() { 
     public void run() { 
      try { 
       thread1 = new Thread() { 
        @Override 
        public void run() { 
         MainFrame frame = new MainFrame(); 
         frame.setVisible(true); 
         start(); 
        } 
       }; 
       thread1.start(); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
    }); 
} 

public MainFrame() { 
    //other stuff and similar Listeners 
    JButton button1 = new JButton(); 
    button1.addActionListener(new ActionAdapter() { 
     @Override 
     public void actionPerformed(ActionEvent ae) { 
      count++; 
      notifyIfTwo(); 
     } 
    }); 
} 

public void notifyIfTwo() { 
    if (count == 2) { 
     synchronized(thread2) { 
      notifyAll(); 
     } 
    } 
} 

public void start() { 
    thread2 = new Thread() { 
     @Override 
     public void run() { 
      try { 
       synchronized(thread1) { 
        thread2.wait(); 
       } 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    }; 
    thread2.start();  
    //other stuff 
} 

不管我怎麼做,我總是得到一個拋出:IllegalMonitorStateException。我也試過用thread2內的一個循環來檢查計數器是否爲2,但是我得到了相同的結果。我認爲它與同步問題有關,但我對整個多線程的新東西很陌生,所以如果能讓我指出正確的方向,我將不勝感激。
或者你甚至可能知道一個更簡單的方法來做整個「等到兩個按鈕按下」 - 問題?

預先感謝,
問候

+0

這甚至沒有編譯!什麼是'線程'?你在騙我們嗎? – Ingo 2013-03-21 12:21:26

+0

沒有編輯過它。犯了一個錯誤簡化了它。這是我想寫的一個小遊戲。我只是想盡可能避免不必要的東西。對不起:) – 2013-03-21 12:23:38

+0

@HolgerPappenstiel你能糾正任何編譯錯誤。例如'Thread.wait()'和'notifyAll()'。這兩個我都希望拋出IllegalMonitorStateExceptions。我喜歡這樣的想法,即您正在嘗試創建一小部分代碼,但該子集至少應該是正確的。你的'run'方法中的'start()'會拋出一個RuntimeException來啓動同一線程兩次 – 2013-03-21 12:29:37

回答

1

我認爲是什麼原因造成的例外是線程1的訪問GUI組件關閉UI線程。解決這個問題的一個方法是擺脫thread1。讓你的onClick(或actionPerformed)處理程序增加變量。讓thread2只是在等待之後循環並監視變量值(比如500mS)。

所以以後可以保持調用,其中可運行,但做的工作像外run方法:

public static void main(String[] args) { 
EventQueue.invokeLater(new Runnable() { 
    public void run() { 
     try 
     { 
      MainFrame frame = new MainFrame(); 
      frame.setVisible(true); 
      start(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
}); 
} 

public void start() { 
thread2 = new Thread() { 
    @Override 
    public void run() { 
     try { 
       while (keepGoing) 
       { 
        thread2.sleep(500); 
        if (variableIncremented) 
        { 
         // doSomething(); 
         // reset variable, or set keepGoing = false 
        } 
       } 
      } 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
}; 
    thread2.start();  
    //other stuff 
} 
+0

剛剛嘗試過。我不再等待IllegalMonitorStateException,但它不會等待我按下按鈕,而是立即跳到下面的方法,這當然會給我一個NPE。 – 2013-03-21 12:41:34

+0

好吧,慢下來。如果變量唯一可以增加的地方是你的按鈕處理程序,另一個方法等待變量增加奇怪的事情發生。在eclipse中調試它,或者將打印語句放在任何地方,因爲我們的一個假設是錯誤的。 – 2013-03-21 12:47:29

+0

也許你想調用「以下方法」,我有「doSomething()」。 – 2013-03-21 12:54:10

3

使用CountDownLatch。它允許等待給定數量的countDown()調用。

Thread.wait();在你的代碼是沒有意義的,它不能編譯。 wait方法可以應用於您正在同步的對象。

1

的一點是:

synchronized(thread2) { 
     notifyAll(); 
    } 

您通知等待this所有線程,但你沒有監視器this。 對於所有的等待/通知/ notifyAll的,代碼必須是:

synchronized (foo) { 
    foo.wait(); // or foo.notify() 
} 

同樣的,以後你:

synchronized(thread1) { 
    thread2.wait(); 
    } 

不能在OBJ1同步,並等待obj2的,除非OBJ1 == obj2的。

+0

好的,謝謝我解決了這個問題。仍然有問題,我在其他答案的評論中描述,雖然 – 2013-03-21 12:47:29

+0

你修復它如何? – Ingo 2013-03-21 12:49:31

+0

我改變它像你顯示,所以我目前已經同步(thread1){\t thread1.notifyAll(); }和synchronized(thread2){thread2.wait(); } – 2013-03-21 13:03:53

0

好吧現在想出來。剩下的問題是我沒有將GUI線程和包含邏輯的其他線程嚴格分開(在我發佈的代碼之外)。
感謝大家幫我弄清了IllegalMonitorStateException。
我現在使用CountDownLatch就像有人建議,它的作品就像一個魅力。