我应该使用什么来获得与Java中的AutoResetEvent等效的语义?(有关 ManualResetEvent,请参阅此问题)。
问问题
9660 次
6 回答
11
@user249654 的回答看起来很有希望。我添加了一些单元测试来验证它,它确实按预期工作。
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);
}
}
具有接受超时的重载的 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;
}
}
于 2012-12-12T10:55:55.323 回答
6
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;
}
}
于 2011-07-06T21:18:53.787 回答
5
我能够让 CyclicBarrier 为我的目的工作。
这是我试图在 Java 中重现的 C# 代码(它只是我编写的用于隔离范例的演示程序,我现在在我编写的 C# 程序中使用它来实时生成视频,以提供对帧速率的准确控制) :
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");
}
}
}
于 2009-07-26T04:01:51.087 回答
3
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();
}
}
}
于 2013-08-04T03:14:51.617 回答
3
如果您想知道您的等待是否以超时或事件集完成(这正是 .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;
}
}
}
于 2015-03-09T15:09:15.607 回答
1
我相信您正在寻找的是 CyclicBarrier 或 CountDownLatch。
于 2009-07-07T13:43:48.783 回答