6

Thread.Sleep()同期メソッドのアクションのループ内で時間間隔を作りたい場合、使用は悪い解決策であると言われました。

一方、プログラムの実行中にアクティブな 2 つの異なるスレッドと 1 つの共有オブジェクトがあり、その共有オブジェクトで Object.wait(long) を使用すると、GUI がしばらくフリーズします。

この問題のより良い解決策は何ですか?


更新コードのこの部分には、GUI で開始されるスレッドの 1 つが含まれています。

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();
    } 
}
4

5 に答える 5

7

同期メソッド内で寝ないでください! GUI イベント ハンドラー/メソッドで待機しないでください。

同期化されたアクションを分割して、Sleep() 呼び出しが GUI スレッド コンテキストで呼び出されないようにします。

たぶん、2 番目のビットには use InvokeLater() を使用します。

于 2012-07-28T11:35:12.813 に答える
4

synchronizeステートメントの範囲を縮小できます。たとえば、メソッド全体で同期している場合

public synchronized void foo()

修飾子を削除して、代わりに同期ブロックを使用できます

synchronized (this) {
   // ...
}

Thread.sleep()可能であれば、このブロックの外側に移動します。共有データの状態を変更するステートメントでのみ同期します。

Swing に関するスレッド化の問題の多くはEvent Dispatcher Threadに関連しており、簡単に解決できます。熟読することをお勧めします。

少し背景、Thread.sleep()同期ブロック内で呼び出してはいけない理由:

ロックを保持しながらスリープまたは待機中。ロックが保持された状態で Thread.sleep を呼び出すと、他のスレッドの進行が長時間妨げられる可能性があるため、重大な活性障害が発生する可能性があります。2 つのロックを保持した状態で Object.wait または Condition.await を呼び出すと、同様の危険が生じます。【JCIP】

于 2012-07-28T11:33:36.140 に答える
0

GUI の処理を​​担当するイベント ディスパッチャ スレッド (EDT) は、非 UI 作業から常に遠ざけてください。また、メソッド全体を同期するのではなく、アトミック ステートメントを同期します。

synchronized(this){
    //...
}
于 2012-07-28T16:17:31.440 に答える
0

私はモニターを利用します: http://www.artima.com/insidejvm/ed2/threadsynch4.html おそらくnotifyまたはnotifyAllで解決できます。幸運を!

于 2012-07-28T11:39:23.717 に答える
-2

この次のコードを試すことができます:

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

delay(5) として呼び出します。コントロールは 5 秒間待機します。

于 2014-09-20T15:53:01.940 に答える