Frage

Was soll ich verwenden Semantik entspricht Autoreset in Java? (Siehe diese Frage für Manual).

War es hilfreich?

Lösung

@ user249654 Antwort vielversprechend aussah. Ich habe einige Unit-Tests um es zu überprüfen, und in der Tat funktioniert es wie erwartet.

Ich habe auch eine Überlastung der waitOne, die eine Auszeit nimmt.

Der Code ist hier, falls jemand anderes findet es nützlich:

Einheit Test

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);
    }
}

Autoreset mit Überlastung, die akzeptiert ein Timeout

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;
    }
}

Andere Tipps

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;
  }
}

Ich war in der Lage zu bekommen CyclicBarrier für meine Zwecke zu arbeiten.

Hier ist der C # -Code ich in Java zu reproduzieren versuchte, (es ist nur ein Demo-Programm ich das Paradigma zu isolieren, schrieb ich es jetzt in C # Programme verwende ich schreiben Video in Echtzeit zu erzeugen, eine genaue Steuerung der zur Verfügung zu stellen Frame-Rate):

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");
            }
        }
    }
}

und hier ist der Java-Code kam ich mit, das Gleiche zu tun (mit der CyclicBarrier Klasse wie in einer früheren Antwort vorgeschlagen):

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");
        }
    }
}

Eine weitere Erweiterung der Lösung aus der akzeptierten Antwort, falls Sie möchten wissen, ob Ihre Warte mit Timeout beendet oder mit Ereignissatz (das ist genau das, was .NET Autoreset des Fall ist).

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();
    }
  }
}

Ich glaube, was Sie suchen ist entweder ein CyclicBarrier oder ein CountDownLatch.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top