如何获得与Java中的AutoResetEvent等效的语义?(有关ManualResetEvent。
@ user249654的答案看起来很有希望。我添加了一些单元测试来验证它,并且确实可以按预期工作。
我还添加了一个重载waitOne,需要超时。
waitOne
如果其他人觉得它有用,则在这里提供代码:
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); } }
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; } }