2013-01-22 4 views
17

Есть ли библиотека на Java, которая выполняет следующие действия? A thread следует повторно sleep за миллисекунды до тех пор, пока условие не станет истинным или не будет достигнуто максимальное время.Сон и проверка до тех пор, пока не будет выполнено условие

Эта ситуация возникает, когда тест ждет, пока какое-то условие станет истинным. На состояние влияет другое thread.

[EDIT] Просто, чтобы сделать его более ясным, я хочу, чтобы тест ожидал только X ms, прежде чем он потерпит неудачу. Он не может ждать навсегда, чтобы состояние стало истинным. Я добавляю надуманный пример.

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 
    } 
} 
+0

Если есть другой поток, контролирующий его, можете ли вы настроить фактический «готовый» сигнал с wait/notify вместо опроса? – Thomas

+0

_ Условие зависит от другого потока. Могу ли я сказать, что я могу использовать _Thread join_ здесь? В любом случае +1 за вопрос. – Amarnath

ответ

0

Вам не следует спать и проверять, а также спать и проверять. Вы хотите подождать переменную условия и изменить условие и разбудить поток, когда его время что-то сделать.

+0

см. Мое улучшенное описание. – Rag

15

EDIT

Большинство ответов сосредоточиться на API низкого уровня с ожидает и оповещает или условий (которые работают более или менее точно так же): трудно получить права, если вы не привыкли к нему. Доказательство. 2 из этих ответов не работают правильно.
java.util.concurrent предлагает вам API высокого уровня, где все эти тонкости были скрыты.

IMHO, нет смысла использовать шаблон ожидания/уведомления, если в параллельном пакете есть встроенный класс, который достигает того же.


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 являются потокобезопасными.

+0

Это действительно лучший ответ, чистое и эффективное решение ... –

-1

Похоже, что вы хотите сделать, это проверить состояние, а затем, если оно ложно ждать до тайм-аута. Затем, в другом потоке, уведомите об этом после завершения операции.

официанта

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 
    } 
} 

Changer

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

Это должно сделать трюк для вас. Вы также можете сделать это, используя блокировку вращения, но вам нужно будет проверять тайм-аут каждый раз, когда вы проходите цикл. Однако код может быть немного проще.

+3

вы не должны использовать wait вне цикла while. – assylias

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; 
     } 
    } 
} 
+0

Точно, 'Condition' или другие решения на основе асинхронности Java в конечном итоге загромождают код и читают действительно неестественно для случаев с сторонними библиотеками, которые не дают никакой точки входа в синхронное ожидание их фоновой обработки. В конечном итоге я использовал «ожидание» даже в не-тестирующем коде, поскольку это наилучшее адаптированное решение в этом случае, особенно с точки зрения удобочитаемости/поддержки. – desseim

Смежные вопросы