2012-07-28 73 views
6

我被告知使用Thread.Sleep()有時候會想要在同步方法的一個循環中執行一些時間間隔。Java中的Thread.Sleep替代

另一方面,我有兩個不同的線程,它們在我的程序的運行時間內都是活動的,並且還有一個共享對象,當我在該共享對象中使用Object.wait(long)時,它會導致我的GUI凍結一段時間。

什麼會是這個問題的更好的解決方案?


更新 代碼的該部分包括被在GUI開始一個線程:

class temperatureUp extends Thread { @Override public void run() { while(true) { try { GBC.increaseTemp(); updateSystemStatus(); } catch(Exception ex) { StringWriter w = new StringWriter(); ex.printStackTrace(new PrintWriter(w)); txtLog.setText(w + "\n" + txtLog.getText()); } } } };

,這是在共享對象中的同步方法,GBC:

public synchronized void increaseTemp() throws InterruptedException{ 
    // don't increase the temperature if the boiler 
    // is not turned on... 
    while (!isBoilerOn) 
     wait(); 

    // increase the current temperature 
    if ((currentTemp + 1) < MAX_TEMP && currentTemp < desiredTemp) { 
     Thread.sleep(2000); ///what should put here if not thread sleep? 
     currentTemp ++;  
     updateGasBoilerStatus(); 
    } 
} 
+1

您必須導致[Event Dispatching Thread](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html)等待。你能提供一個小例子來說明你如何開始你的線程以及何時調用wait()? – theon 2012-07-28 11:33:00

+1

查看['SwingWorker'](http://docs.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html)。此外,請參閱['這個答案'](http://stackoverflow.com/a/11546203/597657)知道它是如何工作的。 – 2012-07-28 11:34:13

+0

@theon我更新了帖子並添加了部分代碼。 – Afflatus 2012-07-28 11:40:49

回答

4

您可以縮小synchronize聲明的範圍。例如,如果你是對整個方法同步

public synchronized void foo() 

您可以刪除修改並使用synchronized塊,而不是

synchronized (this) { 
    // ... 
} 

,如果可能,移動Thread.sleep()超出此塊。只對那些修改共享數據狀態的語句進行同步。

很多關於Swing的線程問題都與Event Dispatcher Thread有關,可以很容易地解決它。我建議你閱讀它。

一點點的背景下,爲什麼你不應該叫Thread.sleep()同步塊內:

睡覺或在持有鎖等待。調用Thread.sleep並鎖定 可以防止其他線程在很長的時間內取得進展,因此具有潛在的嚴重活性危害。調用 帶有兩個鎖的Object.wait或Condition.await會帶來類似的 危害。 [JCIP]

+1

謝謝,我會閱讀關於「事件調度線程」的文章,如果我有其他問題,請回復您。 – Afflatus 2012-07-28 11:51:17

+0

@Elham就你而言,我認爲* Swing *中的併發性的整個章節都會有所幫助,因爲EDT用於更新Swing組件,而同步問題則是關於修改模型的狀態。 – 2012-07-28 11:56:19

+0

實際上更新部分工作得很好。問題是我希望在每次更新後等待,以便用戶可以看到由線程一步一步完成的進程結果。 – Afflatus 2012-07-28 12:51:26

7

不要在同步方法裏面睡覺!不要在GUI事件處理程序/方法中等待!

拆分同步操作,以便在GUI線程上下文中不調用Sleep()調用。

也許可以使用InvokeLater()作爲第二位。

+0

我已經停用了GUI中的睡眠命令。同步方法在另一個類中,正如我所說,它是一個共享對象,同時被兩個不同的線程使用。 – Afflatus 2012-07-28 11:44:56

0

我會利用顯示器:http://www.artima.com/insidejvm/ed2/threadsynch4.html 也許與通知或notifyAll你可以解決它。祝你好運!

+0

謝謝,但事情是等待並通知程序中的線程正常工作。我的問題是我想使它在GUI中的增量顯示會變得更慢,供用戶查看。 – Afflatus 2012-07-28 11:43:01

0

始終保持負責處理GUI的事件調度程序線程(EDT),遠離任何非UI工作。另外,不要同步整個方法,但是同步原子陳述

synchronized(this){ 
    //... 
} 
+0

好的,謝謝,但這將如何成爲我的問題的答案?! – Afflatus 2012-07-29 02:10:34

+0

並且在我的同步方法中唯一的三個動作是在這個序列中必須處於同一個鎖之下的動作。我無法進一步縮小範圍。 – Afflatus 2012-07-29 03:22:18

-1

你可以試試這個下面的代碼:

public static void delay(int waitTime) { 
     long endTime = System.currentTimeMillis() + (waitTime * 1000); 
     while (System.currentTimeMillis() < endTime) {} 
    } 

呼叫時延(5)。控制將等待5秒鐘。

+0

請不要使用它,這是非常混亂。另一種方法是使用java.util.Timer – 2015-04-22 23:22:30