25

次のことを行うJavaのライブラリはありますか? 条件が true になるか、最大時間に達するまで、x ミリ秒間thread繰り返します。sleep

この状況は主に、テストが何らかの条件が真になるのを待っているときに発生します。条件は別の影響を受けthreadます。

[編集] わかりやすくするために、テストが失敗する前に X ミリ秒だけ待機するようにします。条件が真になるのを永遠に待つことはできません。私は不自然な例を追加しています。

class StateHolder{
    boolean active = false;
    StateHolder(){
        new Thread(new Runnable(){
            public void run(){
                active = true;
            }
        }, "State-Changer").start()
    }
    boolean isActive(){
        return active;
    }
}


class StateHolderTest{
    @Test
    public void shouldTurnActive(){
        StateHolder holder = new StateHolder();
        assertTrue(holder.isActive); // i want this call not to fail 
    }
}
4

8 に答える 8

27

編集

ほとんどの回答は、待機と通知または条件 (多かれ少なかれ同じように機能します) を使用した低レベル API に焦点を当てています。慣れていない場合、正しく理解することは困難です。証明: これらの回答のうち 2 つは、待機を正しく使用していません。
java.util.concurrentこれらすべての複雑さが隠されている高レベルの API を提供します。

IMHO、並行パッケージに同じことを達成する組み込みクラスがある場合、待機/通知パターンを使用しても意味がありません。


初期カウントが 1のCountDownLatchは、まさにそれを行います。

  • 条件が真になると、呼び出しますlatch.countdown();
  • 待機中のスレッドで、次を使用します。boolean ok = latch.await(1, TimeUnit.SECONDS);

考案された例:

final CountDownLatch done = new CountDownLatch(1);

new Thread(new Runnable() {

    @Override
    public void run() {
        longProcessing();
        done.countDown();
    }
}).start();

//in your waiting thread:
boolean processingCompleteWithin1Second = done.await(1, TimeUnit.SECONDS);

注: CountDownLatches はスレッド セーフです。

于 2013-01-22T17:32:35.400 に答える
8

を使用する必要がありますCondition

条件に加えてタイムアウトが必要な場合は、を参照してください。await(long time, TimeUnit unit)

于 2013-01-22T17:54:41.117 に答える
1

Awaitility が提供するようなソリューションを探していました。私の質問で間違った例を選んだと思います。私が意味したのは、サードパーティのサービスによって作成された非同期イベントが発生することが予想され、クライアントがサービスを変更して通知を提供できないという状況でした。より合理的な例は、以下のものです。

class ThirdPartyService {

    ThirdPartyService() {
        new Thread() {

            public void run() {
                ServerSocket serverSocket = new ServerSocket(300);
                Socket socket = serverSocket.accept();
                // ... handle socket ...
            }
        }.start();
    }
}

class ThirdPartyTest {

    @Before
    public void startThirdPartyService() {
        new ThirdPartyService();
    }

    @Test
    public void assertThirdPartyServiceBecomesAvailableForService() {
        Client client = new Client();
        Awaitility.await().atMost(50, SECONDS).untilCall(to(client).canConnectTo(300), equalTo(true));
    }
}

class Client {

    public boolean canConnect(int port) {
        try {
            Socket socket = new Socket(port);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}
于 2013-11-28T21:17:18.070 に答える
0

寝てチェックして寝てチェックしてはいけません。条件変数を待機し、条件を変更して、何かを行うときにスレッドを起動したいとします。

于 2013-01-22T17:32:19.753 に答える
-1

あなたがしたいのは、状態をチェックし、それが偽の場合はタイムアウトになるまで待つことのようです。次に、他のスレッドで、操作が完了したらnotifyAllを実行します。

ウェイター

synchronized(sharedObject){
  if(conditionIsFalse){
       sharedObject.wait(timeout);
       if(conditionIsFalse){ //check if this was woken up by a notify or something else
           //report some error
       }
       else{
           //do stuff when true
       }
  }
  else{
      //do stuff when true
  }
}

チェンジャー

  synchronized(sharedObject){
   //do stuff to change the condition
   sharedObject.notifyAll();
 }

それはあなたのためのトリックをするはずです。スピンロックを使用してそれを行うこともできますが、ループを通過するたびにタイムアウトを確認する必要があります。ただし、コードは実際には少し単純かもしれません。

于 2013-01-22T18:07:08.743 に答える