Java-эквивалент .NET ManualResetEvent и WaitHandle - PullRequest
12 голосов
/ 02 сентября 2010

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

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

Ответы [ 4 ]

14 голосов
/ 02 сентября 2010

Рассматривали ли вы вместо этого wait / notify (эквивалент Monitor.Wait и Monitor.Pulse)?

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

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

РЕДАКТИРОВАТЬ: Я только что заметил, что CountDownLatch в основном "одноразового использования" - вы не можете сбросить счет позже, насколько я вижу. Вы можете вместо этого Semaphore. Используйте tryAcquire, как это, чтобы подождать с таймаутом:

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

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

4 голосов
/ 07 июля 2011
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;
  }
}
2 голосов
/ 02 сентября 2010

От: http://www.experts -exchange.com / Программирование / Языки / 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
       //...
   }
}
1 голос
/ 17 октября 2012

Теоретически, класс ManualResetEvent, как указано выше, корректен на Java 5 (но не ранее). Учитывая долгую историю неправильных (или неадекватных) реализаций volatile, мне кажется разумнее добавить дополнительный синхронизированный блок в reset (), чтобы создать гарантированный барьер записи и обеспечить полную атомарность. Опасность заключается в том, что чтение «open» может пропустить запись «open» на многопроцессорном процессоре 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;
        }
      }
   }

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...