Javaに以下を実行するライブラリはありますか?thread
は、条件がtrueになるか、最大時間に達するまで、xミリ秒間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
}
}
[〜#〜]編集[〜#〜]
ほとんどの回答は、待機と通知または条件(多かれ少なかれ同じように機能します)を使用した低レベルAPIに焦点を当てています。慣れていない場合、正しく理解することは困難です。証明:これらの回答のうち2つは、待機を正しく使用しません。
_Java.util.concurrent
_ は、これらすべての複雑さが隠されている高レベルのAPIを提供します。
私見、コンカレントパッケージに同じことを実現する組み込みクラスがある場合、待機/通知パターンを使用しても意味がありません。
CountDownLatch の初期カウントが1の場合、正確に次のようになります。
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はスレッドセーフです。
Awaitility はシンプルでクリーンなソリューションを提供します:
await().atMost(10, SECONDS).until(() -> condition());
Condition
を使用する必要があります。
条件に加えてタイムアウトを設定したい場合は、 await(long time, TimeUnit unit)
を参照してください
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;
}
}
}
寝てチェックして寝てチェックしてはいけません。条件変数で待機し、条件を変更して、何かを実行するときにスレッドを起動したいとします。
私はこの機能的なインターフェイスを利用したこの普遍的な方法を適用することによってこの問題を解決しました:
private void waitUntilConditionIsMet(BooleanSupplier awaitedCondition, int timeoutInSec) {
boolean done;
long startTime = System.currentTimeMillis();
do {
done = awaitedCondition.getAsBoolean();
} while (!done && System.currentTimeMillis() - startTime < timeoutInSec * 1000);
}
次に、以下を実装できます。
class StateHolderTest{
@Test
public void shouldTurnActive(){
StateHolder holder = new StateHolder();
waitUntilConditionIsMet(() -> holder.isActive(), 10);
assertTrue(holder.isActive);
}
}