What is java's equivalent of ManualResetEvent? [duplicate]
Asked Answered
D

5

34

What is java's equivalent of ManualResetEvent?

Depute answered 30/6, 2009 at 16:9 Comment(0)
E
20

The closest I know of is the Semaphore. Just use it with a "permit" count of 1, and acquire/release will be pretty much the same as what you know from the ManualResetEvent.

A semaphore initialized to one, and which is used such that it only has at most one permit available, can serve as a mutual exclusion lock. This is more commonly known as a binary semaphore, because it only has two states: one permit available, or zero permits available. When used in this way, the binary semaphore has the property (unlike many Lock implementations), that the "lock" can be released by a thread other than the owner (as semaphores have no notion of ownership). This can be useful in some specialized contexts, such as deadlock recovery.

Escorial answered 30/6, 2009 at 16:14 Comment(6)
I don't think this can work without a race condition (assuming a thread cannot release a semaphore it did not previously acquire itself)Depute
I take it back - from the documentation it appears a semaphore can be released without ever taking it.Depute
Yeah, that's because semaphores have no ownership notion. They are pretty much synchronized counters which have threads wait if the counter is 0.Escorial
If semaphore is released multiple times without proper aquire, then availiblePermits will be greater than 1 and it will not behave the same way as ManulResetEvent would since reset() will not cause the waitOne() to wait.Desireedesiri
Once you Set a ManualResetEvent it's permanently open, all current and future Waits will pass. Semaphore once acquired to let one thread pass, will stop all other threads. Closest thing would be to call release immediately after each acquire, but that's still plenty of overhead and micro-blocking.Norean
@Norean You're of course correct, there needs to be an immediate release for it to mimick the ManualResetEvent, otherwise you have a AutoResetEvent. As I wrote, this is just the closest sync primitive I'm aware of in Java. A common use of the ManualResetEvent is for one thread to wait for the synchronization, and that use-case will not suffer from micro-blocking (this would only happen if multiple threads wait at once at the event) and the overhead should be fairly small (comparable to the monitor solution offered in another answer).Escorial
B
28
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 boolean waitOne(long milliseconds) throws InterruptedException {
    synchronized (monitor) {
      if (open) 
        return true;
      monitor.wait(milliseconds);
        return open;
    }
  }

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

  public void reset() {//close stop
    open = false;
  }
}
Brame answered 13/1, 2010 at 9:25 Comment(5)
That looks like it will not work at all: thread one calls waitOne() and blocks in monitor.wait(). Thread two calls set and blocks on synchronized (monitor). This is the only use case, right? I think it's okay if you just leave out synchronized statement in set.Bloomsbury
@LimitedAtonement: in Java you must be in a synchronized block in order to wait on an object. During the wait, the monitor lock of that object is released, so it can be acquired in another thread. See docs.oracle.com/javase/tutorial/essential/concurrency/…Bacciferous
@WayneUroda My bad. I guess I shouldn't ask you why one has to be in a synchronized block in order to then release the lock by calling wait. I'm sure that's as old as the hills ;) .Bloomsbury
@LimitedAtonement in other languages you can wait/notify on similar entities without having to have them locked (C# IIRC, win32/GDI, etc). I think that it is done in java this way to help the programmer avoid some common race conditions. Maybe this can explain better than I can :) #2779984Bacciferous
its work fine! and its correct implementation ManualResetEvent in java. All other implementation or bad or complexBrame
E
20

The closest I know of is the Semaphore. Just use it with a "permit" count of 1, and acquire/release will be pretty much the same as what you know from the ManualResetEvent.

A semaphore initialized to one, and which is used such that it only has at most one permit available, can serve as a mutual exclusion lock. This is more commonly known as a binary semaphore, because it only has two states: one permit available, or zero permits available. When used in this way, the binary semaphore has the property (unlike many Lock implementations), that the "lock" can be released by a thread other than the owner (as semaphores have no notion of ownership). This can be useful in some specialized contexts, such as deadlock recovery.

Escorial answered 30/6, 2009 at 16:14 Comment(6)
I don't think this can work without a race condition (assuming a thread cannot release a semaphore it did not previously acquire itself)Depute
I take it back - from the documentation it appears a semaphore can be released without ever taking it.Depute
Yeah, that's because semaphores have no ownership notion. They are pretty much synchronized counters which have threads wait if the counter is 0.Escorial
If semaphore is released multiple times without proper aquire, then availiblePermits will be greater than 1 and it will not behave the same way as ManulResetEvent would since reset() will not cause the waitOne() to wait.Desireedesiri
Once you Set a ManualResetEvent it's permanently open, all current and future Waits will pass. Semaphore once acquired to let one thread pass, will stop all other threads. Closest thing would be to call release immediately after each acquire, but that's still plenty of overhead and micro-blocking.Norean
@Norean You're of course correct, there needs to be an immediate release for it to mimick the ManualResetEvent, otherwise you have a AutoResetEvent. As I wrote, this is just the closest sync primitive I'm aware of in Java. A common use of the ManualResetEvent is for one thread to wait for the synchronization, and that use-case will not suffer from micro-blocking (this would only happen if multiple threads wait at once at the event) and the overhead should be fairly small (comparable to the monitor solution offered in another answer).Escorial
F
10

Try CountDownLatch with count of one.

CountDownLatch startSignal = new CountDownLatch(1);
Frannie answered 30/6, 2009 at 16:17 Comment(1)
The problem with CountDownLatch is that it's not reusable. Once the latch reaches 0, it can't be used anymore. It can be replaced with a new latch instance, but this can create race conditions unless done right.Depute
I
3

Based on:

ManualResetEvent allows threads to communicate with each other by signaling. Typically, this communication concerns a task which one thread must complete before other threads can proceed.

from here:

http://msdn.microsoft.com/en-us/library/system.threading.manualresetevent.aspx

you possibly want to look at the Barriers in the Java concurrency package - specifically CyclicBarrier I believe:

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

It blocks a fixed number of threads until a particular event has occured. All the threads must come together at a barrier point.

Imprecision answered 30/6, 2009 at 16:17 Comment(4)
can you provide some examples of that Barrier? I didn't get the example from documentation.Rihana
Oh, I've found an article: tutorials.jenkov.com/java-util-concurrent/cyclicbarrier.html So it blocks till all threads wil reach the barrier (so critical mass is formed) and then it shall continue. Quite isntersting. Now I'll know this thing. Unfortunately it's not so usefull for question, but it comes so, that each java Object has wait, shich is ManualResetEventRihana
@BogdanMart But it re-blocks automatically, which means it's neither ManualResetEvent nor AutoResetEvent.Norean
@BogdanMart I wasn't talking about other answers. I was talking about how your comment is not true and misleading other readers.Norean
G
2

I believe the crux of the .NET MRE is thread affinity and its ability to let all waiting threads go through when Set is called. I found the use of the Semaphore works well. However, if I get 10 or 15 threads waiting, then I run into another issue. Specifically, it occurs when Set is called. In .Net, all waiting threads are released. Using a semphore does not release all. So I wrapped it in a class. NOTE: I am very familiar with .NET threading. I am relatively new to Java threading and synchronization. Nevertheless, I am willing to jump in and get some real feedback. Here's my implementation with assumptions that a Java novice would make:

public class ManualEvent {
private final static int MAX_WAIT = 1000;
private final static String TAG = "ManualEvent"; 
private Semaphore semaphore = new Semaphore(MAX_WAIT, false);

private volatile boolean signaled = false;
public ManualEvent(boolean signaled) {
    this.signaled = signaled; 
    if (!signaled) {
        semaphore.drainPermits();
    }
}

public boolean WaitOne() {
    return WaitOne(Long.MAX_VALUE);
}

private volatile int count = 0;
public boolean WaitOne(long millis) {
    boolean bRc = true;
    if (signaled)
        return true;

    try {
        ++count;
        if (count > MAX_WAIT) {
            Log.w(TAG, "More requests than waits: " + String.valueOf(count));
        }

        Log.d(TAG, "ManualEvent WaitOne Entered");
        bRc = semaphore.tryAcquire(millis, TimeUnit.MILLISECONDS);
        Log.d(TAG, "ManualEvent WaitOne=" + String.valueOf(bRc));
    }
    catch (InterruptedException e) {
        bRc = false;
    }
    finally {
        --count;
    }

    Log.d(TAG, "ManualEvent WaitOne Exit");
    return bRc;
}

public void Set() {
    Log.d(TAG, "ManualEvent Set");
    signaled = true;
    semaphore.release(MAX_WAIT);
}

public void Reset() {
    signaled = false;
    //stop any new requests
    int count = semaphore.drainPermits();
    Log.d(TAG, "ManualEvent Reset: Permits drained=" + String.valueOf(count));
}

}

Also note that I am basically betting that there's no more than a 1000 requests waiting for a release at any given time. By releasing and aquiring in batches, I am attempting to release any waiting threads. Note the call to WaitOne is working 1 permit at a time.

Garica answered 24/11, 2009 at 6:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.