Java는 .NET의 Autoresetevent와 동일합니까?
-
11-09-2019 - |
문제
의미론을 얻기 위해 무엇을 사용해야합니까? autoresetevent 자바에서? (보다 이 질문 ManualResetevent의 경우).
해결책
@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;
}
}
다른 팁
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# 프로그램에서 사용합니다). :
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;
}
}
}
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();
}
}
}
나는 당신이 찾고있는 것이 Cyclicbarrier 또는 CountdownLatch라고 생각합니다.
제휴하지 않습니다 StackOverflow