Java相当于.Net的AutoResetEvent?

我应该使用什么来获得与Java中的AutoResetEvent等效的语义? (请参阅ManualResetEvent的此问题 )。

@ user249654的答案看起来很有希望。 我添加了一些unit testing来validation它,确实它按预期工作。

我还添加了一个waitOne超时的waitOne重载。

代码在这里以防其他人发现它有用:

unit testing

 import org.junit.Assert; import org.junit.Test; import static java.lang.System.currentTimeMillis; /** * @author Drew Noakes http://drewnoakes.com */ public class AutoResetEventTest { @Test public void synchronisesProperly() throws InterruptedException { final AutoResetEvent event1 = new AutoResetEvent(false); final AutoResetEvent event2 = new AutoResetEvent(false); final int loopCount = 10; final int sleepMillis = 50; Thread thread1 = new Thread(new Runnable() { @Override public void run() { try { for (int i = 0; i < loopCount; i++) { long t = currentTimeMillis(); event1.waitOne(); Assert.assertTrue("Time to wait should be within 5ms of sleep time", Math.abs(currentTimeMillis() - t - sleepMillis) < 5); Thread.sleep(sleepMillis); t = currentTimeMillis(); event2.set(); Assert.assertTrue("Time to set should be within 1ms", currentTimeMillis() - t <= 1); } } catch (InterruptedException e) { Assert.fail(); } } }); Thread thread2 = new Thread(new Runnable() { @Override public void run() { try { for (int i = 0; i < loopCount; i++) { Thread.sleep(sleepMillis); long t = currentTimeMillis(); event1.set(); Assert.assertTrue("Time to set should be within 1ms", currentTimeMillis() - t <= 1); t = currentTimeMillis(); event2.waitOne(); Assert.assertTrue("Time to wait should be within 5ms of sleep time", Math.abs(currentTimeMillis() - t - sleepMillis) < 5); } } catch (InterruptedException e) { Assert.fail(); } } }); long t = currentTimeMillis(); thread1.start(); thread2.start(); int maxTimeMillis = loopCount * sleepMillis * 2 * 2; thread1.join(maxTimeMillis); thread2.join(maxTimeMillis); Assert.assertTrue("Thread should not be blocked.", currentTimeMillis() - t < maxTimeMillis); } @Test public void timeout() throws InterruptedException { AutoResetEvent event = new AutoResetEvent(false); int timeoutMillis = 100; long t = currentTimeMillis(); event.waitOne(timeoutMillis); long took = currentTimeMillis() - t; Assert.assertTrue("Timeout should have occurred, taking within 5ms of the timeout period, but took " + took, Math.abs(took - timeoutMillis) < 5); } @Test public void noBlockIfInitiallyOpen() throws InterruptedException { AutoResetEvent event = new AutoResetEvent(true); long t = currentTimeMillis(); event.waitOne(200); Assert.assertTrue("Should not have taken very long to wait when already open", Math.abs(currentTimeMillis() - t) < 5); } } 

具有接受超时的重载的AutoResetEvent

 public class AutoResetEvent { private final Object _monitor = new Object(); private volatile boolean _isOpen = false; public AutoResetEvent(boolean open) { _isOpen = open; } public void waitOne() throws InterruptedException { synchronized (_monitor) { while (!_isOpen) { _monitor.wait(); } _isOpen = false; } } public void waitOne(long timeout) throws InterruptedException { synchronized (_monitor) { long t = System.currentTimeMillis(); while (!_isOpen) { _monitor.wait(timeout); // Check for timeout if (System.currentTimeMillis() - t >= timeout) break; } _isOpen = false; } } public void set() { synchronized (_monitor) { _isOpen = true; _monitor.notify(); } } public void reset() { _isOpen = false; } } 
 class AutoResetEvent { private final Object monitor = new Object(); private volatile boolean open = false; public AutoResetEvent(boolean open) { this.open = open; } public void waitOne() throws InterruptedException { synchronized (monitor) { while (open == false) { monitor.wait(); } open = false; // close for other } } public void set() { synchronized (monitor) { open = true; monitor.notify(); // open one } } public void reset() {//close stop open = false; } } 

我能够让CyclicBarrier为我的目的而工作。

这是我试图用Java重现的C#代码(它只是我编写的一个演示程序来隔离范例,我现在在C#程序中使用它来编写实时生成video,以提供准确的帧速率控制) :

 using System; using System.Timers; using System.Threading; namespace TimerTest { class Program { static AutoResetEvent are = new AutoResetEvent(false); static void Main(string[] args) { System.Timers.Timer t = new System.Timers.Timer(1000); t.Elapsed += new ElapsedEventHandler(delegate { are.Set(); }); t.Enabled = true; while (true) { are.WaitOne(); Console.WriteLine("main"); } } } } 

这是我提出的用于执行相同操作的Java代码(使用上一个答案中建议的CyclicBarrier类):

 import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.CyclicBarrier; public class TimerTest2 { static CyclicBarrier cb; static class MyTimerTask extends TimerTask { private CyclicBarrier cb; public MyTimerTask(CyclicBarrier c) { cb = c; } public void run() { try { cb.await(); } catch (Exception e) { } } } public static void main(String[] args) { cb = new CyclicBarrier(2); Timer t = new Timer(); t.schedule(new MyTimerTask(cb), 1000, 1000); while (true) { try { cb.await(); } catch (Exception e) { } System.out.println("main"); } } } 

如果您想知道等待是以超时还是事件设置完成(这正是.NET AutoResetEvent所做的那样),那么可以从接受的答案中再扩展一个解决方案。

 public boolean waitOne(long timeout) throws InterruptedException { synchronized (monitor) { try { long t = System.currentTimeMillis(); while (!isOpen) { monitor.wait(timeout); // Check for timeout if (System.currentTimeMillis() - t >= timeout) break; } return isOpen; } finally { isOpen = false; } } } 

我相信你要找的是CyclicBarrier或CountDownLatch。

 import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class AutoResetEvent { private volatile boolean _signaled; private ReentrantLock _lock; private Condition _condition; public AutoResetEvent(boolean initialState) { _signaled = initialState; _lock = new ReentrantLock(); _condition = _lock.newCondition(); } public void waitOne(long miliSecond) throws InterruptedException { _lock.lock(); try { while (!_signaled) _condition.await(miliSecond, TimeUnit.MILLISECONDS); _signaled = false; } finally { _lock.unlock(); } } public void waitOne() throws InterruptedException { _lock.lock(); try { while (!_signaled) _condition.await(); _signaled = false; } finally { _lock.unlock(); } } public void set() { _lock.lock(); try { _condition.signal(); _signaled = true; } finally { _lock.unlock(); } } public void reset() { _lock.lock(); try { _signaled = false; } finally { _lock.unlock(); } } } 
Interesting Posts