Java Equivalent.NET ManualResetEvent и WaitHandle

Я хотел бы знать, поддерживает ли Java эквивалент классов .NET ManualResetEvent и WaitHandle, так как я бы хотел написать код, который блокирует данный тайм-аут, если событие не инициировано.

.NET-классы WaitHandle и ManualResetEvent обеспечивают приятный, беспроблемный интерфейс для того, что также является потокобезопасным, насколько я знаю, поэтому что может предложить Java?

Ответ 1

Считаете ли вы использование wait/notify (эквивалент Monitor.Wait и Monitor.Pulse) вместо?

Вам нужно немного проверить, действительно ли вам нужно ждать (чтобы избежать условий гонки), но он должен работать.

В противном случае что-то вроде CountDownLatch может сделать то, что вы хотите.

EDIT: Я только заметил, что CountDownLatch в основном "одноразовый" - вы не можете reset подсчитать позже, насколько я могу видеть. Возможно, вы захотите Semaphore. Используйте tryAcquire, чтобы подождать с таймаутом:

if (semaphore.tryAquire(5, TimeUnit.SECONDS)) {
   ...
   // Permit was granted before timeout
} else {
   // We timed out while waiting
}

Обратите внимание, что это отличается от ManualResetEvent тем, что каждый успешный вызов tryAcquire уменьшает количество разрешений, поэтому в итоге они снова закончатся. Вы не можете сделать это надолго "установленным", как вы могли, с помощью ManualResetEvent. (Это будет работать с CountDownLatch, но тогда вы не смогли бы "reset":)

Ответ 2

class ManualResetEvent {

  private final Object monitor = new Object();
  private volatile boolean open = false;

  public ManualResetEvent(boolean open) {
    this.open = open;
  }

  public void waitOne() throws InterruptedException {
    synchronized (monitor) {
      while (open==false) {
          monitor.wait();
      }
    }
  }

  public void set() {//open start
    synchronized (monitor) {
      open = true;
      monitor.notifyAll();
    }
  }

  public void reset() {//close stop
    open = false;
  }
}

Ответ 3

От: http://www.experts-exchange.com/Programming/Languages/Java/Q_22076798.html

Привет, вы можете добиться синхронизации, используя класс java.util.concurrent.Semaphore(используйте разрешение 0).

http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/Semaphore.html

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

import java.util.concurrent.Semaphore;

class ScalesCommunication {

   private static Semaphore sem = new Semaphore(0);

   // called by thread 1
   void readLoop() {
      //...

      //after connection established, release semaphore (value incremented by 1)
      sem.release();
   }

   // called by thread 2
   String sendCommand(String command) {

       sem.acquire(); // thread waits here if sem value == 0

       // at this point connection is established
       //...
   }
}

Ответ 4

В теории класс ManualResetEvent, как указано выше, верен на Java 5 (но не ранее). Учитывая долгую историю неправильных (или неадекватных) реализаций изменчивости, мне кажется разумнее добавить дополнительный синхронизированный блок в reset(), чтобы создать гарантированный барьер записи и обеспечить полную атомарность. Опасность состоит в том, что чтение "открытого" может передать запись "открытого" на многопроцессорном процессоре Intel. Преимущество приведенного ниже изменения: оно может оказаться неэффективным, но оно имеет большое преимущество, гарантируемое быть неправым, при очень небольших дополнительных затратах.

   class ManualResetEvent {
      private final Object monitor = new Object();
      private volatile boolean open = false;

      public ManualResetEvent(boolean open) {
        this.open = open;   }

      public void waitOne() throws InterruptedException {
        synchronized (monitor) {
          while (open==false) {
              monitor.wait();
          }
        }
      }

      public void set() {//open start
        synchronized (monitor) {
          open = true;
          monitor.notifyAll();
        }
      }

      public void reset() {//close stop
        synchronized(monitor) {
           open = false;
        }
      }
   }

Благодаря оригинальному плакату.