I need to write some byte to the serial connection. However I can not find something in JSSC library to set a write timeout. I need this timeout because if I set the hardware flowcontrol and I remove the cable my application is stuck waiting the CTS signal.
UPDATE
I tried this workaround with Future object:
ExecutorService executor = Executors.newSingleThreadExecutor();
...
public synchronized void write(byte[] content, int timeout) throws InterruptedException, SerialPortException{
long starttime = System.currentTimeMillis();
Future<Boolean> future = executor.submit(new Callable<Boolean>() {
public Boolean call() throws Exception {
serialPort.writeBytes(content);
return new Boolean(true);
}
});
try {
future.get(timeout, TimeUnit.MILLISECONDS);
log.debug("Duration: {}",DurationFormatUtils.formatDuration(System.currentTimeMillis() - starttime, "mm:ss.SS"));
} catch (ExecutionException e) {
throw new HardwareException(e.getMessage());
} catch (TimeoutException e) {
throw new HardwareException("Impossibile scrivere nella porta seriale (timeout)");
}
}
But it doesn't work very well, it take 4s to write 550byte via COM port 256000 baud...
Trying a direct write:
public synchronized void write(byte[] content, int timeout) throws InterruptedException, SerialPortException{
try {
long starttime = System.currentTimeMillis();
serialPort.writeBytes(content);
log.debug("Duration: {}",DurationFormatUtils.formatDuration(System.currentTimeMillis() - starttime, "mm:ss.SS"));
} catch (SerialPortException e) {
throw new HardwareException(e.getMessage());
}
}
It took 0.5s as expected!
The problem seems to be the "syncronized" keyword in the main method, why?
I had the same problem. I solved it by launching two threads : one to write one to wait for a specific amount of time. Depending one the first one that finishes, the writing is a success or a timeout. Here are the different classes I used :
ByteWriter : an interface for a generic byte writing (I wanted to be able to switch from JSSC to any other framework
package net.femtoparsec.jssc;
import java.io.IOException;
public interface ByteWriter {
void write(byte[] bytes) throws IOException;
void write(byte oneByte) throws IOException;
void write(byte[] bytes, long timeout) throws IOException, InterruptedException;
void write(byte oneByte, long timeout) throws IOException, InterruptedException;
void cancelWrite() throws IOException;
}
JsscByteWriter : an implementation of ByteWriter for Jssc
package net.femtoparsec.jssc;
import jssc.SerialPort;
import jssc.SerialPortException;
import java.io.IOException;
public class JsscByteWriter implements ByteWriter {
private final SerialPort serialPort;
public JsscByteWriter(SerialPort serialPort) {
this.serialPort = serialPort;
}
#Override
public void cancelWrite() throws IOException {
try {
serialPort.purgePort(SerialPort.PURGE_TXABORT);
serialPort.purgePort(SerialPort.PURGE_TXCLEAR);
} catch (SerialPortException e) {
throw new IOException(e);
}
}
#Override
public void write(byte[] bytes) throws IOException {
try {
serialPort.writeBytes(bytes);
} catch (SerialPortException e) {
throw new IOException(e);
}
}
#Override
public void write(byte oneByte) throws IOException {
try {
serialPort.writeByte(oneByte);
} catch (SerialPortException e) {
throw new IOException(e);
}
}
#Override
public void write(byte[] bytes, long timeout) throws IOException, InterruptedException {
if (timeout <= 0) {
this.write(bytes);
}
else {
new TimedOutByteWriting(this, bytes, timeout).write();
}
}
#Override
public void write(byte oneByte, long timeout) throws IOException, InterruptedException {
if (timeout <= 0) {
this.write(oneByte);
}
else {
new TimedOutByteWriting(this, oneByte, timeout).write();
}
}
}
TimedOutByteWriting : the class to perform the writing timeout.
package net.femtoparsec.jssc;
import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.*;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class TimedOutByteWriting {
private final ByteWriter byteWriter;
private final boolean onlyOneByte;
private final byte oneByte;
private final byte[] bytes;
private final long timeout;
private static final ExecutorService EXECUTOR_SERVICE = Executors.newCachedThreadPool(r -> {
Thread t = new Thread(r, "TimedOutByteWriting Thread");
t.setDaemon(true);
return t;
});
TimedOutByteWriting(ByteWriter byteWriter, byte oneByte, long timeout) {
if (timeout <= 0) {
throw new IllegalArgumentException("Invalid time out value : "+timeout+". Must be greater than 0");
}
this.byteWriter = Objects.requireNonNull(byteWriter, "byteWriter");
this.bytes = null;
this.oneByte = oneByte;
this.timeout = timeout;
this.onlyOneByte = true;
}
TimedOutByteWriting(ByteWriter byteWriter, byte[] bytes, long timeout) {
if (timeout <= 0) {
throw new IllegalArgumentException("Invalid time out value : "+timeout+". Must be greater than 0");
}
this.byteWriter = Objects.requireNonNull(byteWriter, "byteWriter");
this.bytes = Objects.requireNonNull(bytes, "bytes");
this.timeout = timeout;
this.oneByte = 0;
this.onlyOneByte = false;
}
void write() throws IOException, InterruptedException {
final Lock lock = new ReentrantLock();
final Condition condition = lock.newCondition();
final Result result = new Result();
final Future<?> writeThread = EXECUTOR_SERVICE.submit(new WriteRunnable(result, lock, condition));
final Future<?> timeoutThread = EXECUTOR_SERVICE.submit(new TimeoutRunnable(result, lock, condition));
lock.lock();
try {
if (!result.timedout && !result.writeDone) {
try {
condition.await();
} catch (InterruptedException e) {
writeThread.cancel(true);
timeoutThread.cancel(true);
throw e;
}
}
if (!result.writeDone) {
byteWriter.cancelWrite();
}
else {
timeoutThread.cancel(true);
}
}
finally {
lock.unlock();
}
result.handleResult();
}
private abstract class TimedOutByteWritingRunnable implements Runnable {
protected final Result result;
final Lock lock;
final Condition condition;
TimedOutByteWritingRunnable(Result result, Lock lock, Condition condition) {
this.result = result;
this.lock = lock;
this.condition = condition;
}
}
private class WriteRunnable extends TimedOutByteWritingRunnable {
private WriteRunnable(Result result, Lock lock, Condition condition) {
super(result, lock, condition);
}
#Override
public void run() {
IOException exception;
try {
if (onlyOneByte) {
byteWriter.write(oneByte);
} else {
byteWriter.write(bytes);
}
exception = null;
} catch (IOException e) {
exception = e;
}
lock.lock();
try {
result.writeException = exception;
result.writeDone = exception == null;
condition.signalAll();
} finally {
lock.unlock();
}
}
}
private class TimeoutRunnable extends TimedOutByteWritingRunnable {
private TimeoutRunnable(Result result, Lock lock, Condition condition) {
super(result, lock, condition);
}
#Override
public void run() {
boolean interrupted;
try {
TimeUnit.MILLISECONDS.sleep(timeout);
interrupted = false;
} catch (InterruptedException e) {
interrupted = true;
}
lock.lock();
try {
result.timedout = !interrupted;
condition.signalAll();
} finally {
lock.unlock();
}
}
}
private static class Result {
IOException writeException;
boolean writeDone = false;
boolean timedout = false;
void handleResult() throws IOException {
if (writeDone) {
return;
}
if (timedout) {
throw new TimeoutException("Write timed out");
}
else if (writeException != null) {
throw writeException;
}
}
}
}
And the TimeOutException
package net.femtoparsec.jssc;
import java.io.IOException;
public class TimeoutException extends IOException {
public TimeoutException(String message) {
super(message);
}
}
Then, simply create a JsscByteWriter and use the methods with the timeout parameter to write with a timeout.
When using flow control write will block if threshold is reached to prevent buffer overflow. For example if XOFF character has been received then driver or OS will not allow serial port to send data to remote end. The above approach like canceling the thread may leave serial port operation in inconsistent state if overlapped IO (windows) is used. We are manipulating things in java layer but what about native layer. Please correct me if I missed something.
Consider using other serial port library like SCM or modify the jssc's native code to handle such situations.
Related
In listing 7.15 of "Java Concurrency in Practice" there is an example of producer/consumer with no wait for termination on the method stop.
The main thread in the original code does not wait for the log thread to finish. This can cause issue especially when logging to a file and the file needs to be manipulated after the stop. An exception can be generated if the consumer is still using the file.
Does the following code work adding wait for termination with timeout on the stop method?
public class LogService {
private final BlockingQueue<String> queue;
private final LoggerThread loggerThread;
private final PrintWriter writer;
private final Object lock;
private boolean shutdown;
private boolean prepareShutdown;
private int reservations;
public LogService(Writer writer) {
this.queue = new LinkedBlockingQueue<String>();
this.loggerThread = new LoggerThread();
this.writer = new PrintWriter(writer);
this.lock = new Object();
}
public void start() {
loggerThread.start();
}
public void stop(long timeout) throws InterruptedException {
synchronized (lock) {
prepareShutdown = true;
}
loggerThread.interrupt();
try {
loggerThread.join(timeout);
} finally {
synchronized (lock) {
shutdown = true;
}
loggerThread.interrupt();
}
}
public void log(String msg) throws InterruptedException {
synchronized (lock) {
if (shutdown || prepareShutdown)
throw new IllegalStateException(/* ... */);
++reservations;
}
queue.put(msg);
}
private class LoggerThread extends Thread {
public void run() {
try {
while (true) {
try {
synchronized (lock) {
if (shutdown || prepareShutdown
&& reservations == 0)
break;
}
String msg = queue.take();
synchronized (lock) {
--reservations;
}
writer.println(msg);
} catch (InterruptedException e) { /* retry */
}
}
} finally {
writer.close();
}
}
}
}
I have an synchronous execution path which needs to either complete or timeout within a given time frame.
Let's say I have a class with a main() method in which I invoke method A(), which in-turn calls B(), and that in-turn calls C(), of the same or different classes, all synchronous, and without using an external resource like database , webservice, or file system (so not blocking IO, it's more like a CPU or memory intensive computation).
How do I code for its timeout in Java? I have looked at TimerTask but that is more of making the flow async and for scheduling tasks. Any other suggestions?
You should use ExecutorService to do that
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(new Callable() {
public String call() throws Exception {
//do operations you want
return "OK";
}
});
try {
System.out.println(future.get(2, TimeUnit.SECONDS)); //timeout is in 2 seconds
} catch (TimeoutException e) {
System.err.println("Timeout");
}
executor.shutdownNow();
You can run a parallel thread which will wait for the specified timeout and interrupt the current thread, and then run A(). However a, b and c must be interruptible, that is to check periodically current thread interrupted flag and throw InterruptedException, otherwise it wont work
final Thread current = Thread.currentThread();
Thread timer = new Thread() {
public void run() {
try {
Thread.sleep(5000);
current.interrupt();
} catch (InterruptedException e) {
// timer stopped
}
};
};
try {
A(); // this throws InterruptedException if interrupted by timer
timer.interrupt(); // no timeout lets stop the timer
} catch (InterruptedException e) {
// timeout
}
You can't do an synchronous call with a timeout but you can emulate it using a second thread. This is an example to do that:
package com.ardevco.example;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
class ExceptionThrower {
public static <R> R throwUnchecked(Throwable t) {
return ExceptionThrower.<RuntimeException, R> trhow0(t);
}
#SuppressWarnings("unchecked")
private static <E extends Throwable, R> R trhow0(Throwable t) throws E {
throw (E) t;
}
}
class TestApplicationException1 extends Exception {
private static final long serialVersionUID = 1L;
public TestApplicationException1(String string) {
super(string);
}
};
class TestApplicationException2 extends Exception {
private static final long serialVersionUID = 1L;
public TestApplicationException2(String string) {
super(string);
}
};
class TestApplicationTimeoutException extends Exception {
private static final long serialVersionUID = 1L;
public TestApplicationTimeoutException(String string) {
super(string);
};
}
public class SynchronousTimeoutTester {
public static final long SYNC_METHOD_TIMEOUT_IN_MILLISECONDS = 2000L;
private final ExecutorService executorService = Executors.newSingleThreadExecutor();
public static void main(String[] args) {
SynchronousTimeoutTester tester = new SynchronousTimeoutTester();
/* call the method asynchronously 10 times */
for (int i = 0; i < 10; i++) {
try {
System.out.println("Result sync call: " + tester.getAsynchTest());
}
catch (TestApplicationException1 e) {
System.out.println("catched as TestApplicationException1: " + e);
}
catch (TestApplicationException2 e) {
System.out.println("catched as TestApplicationException2: " + e);
}
catch (TestApplicationTimeoutException e) {
System.out.println("catched as TestApplicationTimeoutException: " + e);
}
catch (InterruptedException e) {
System.out.println("catched as InterruptedException: " + e);
}
catch (Exception e) {
System.out.println("catched as Exception: " + e);
}
}
tester.shutdown();
}
private void shutdown() {
executorService.shutdown();
try {
executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
}
catch (InterruptedException e) {
System.out.println("Error stopping threadpool:" + e);
}
}
private Integer testAsynch() throws TestApplicationException1, TestApplicationException2, InterruptedException {
Random random = new Random();
switch (random.nextInt(10)) {
case 0:
return 0;
case 1:
throw new TestApplicationException1("thrown TestApplicationException1");
case 2:
throw new TestApplicationException2("thrown TestApplicationException2");
case 3:
Thread.sleep(10000L);
return -1;
case 4:
throw new RuntimeException("thrown Exception");
default:
return random.nextInt(10);
}
}
private Integer getAsynchTest() throws TestApplicationException1, TestApplicationException2, Exception {
Integer dummy = null;
Future<Integer> testAsynchF = executorService.submit(
new Callable<Integer>() {
public Integer call() throws Exception {
return testAsynch();
}
});
try {
dummy = testAsynchF.get(SynchronousTimeoutTester.SYNC_METHOD_TIMEOUT_IN_MILLISECONDS, TimeUnit.MILLISECONDS);
}
catch (ExecutionException e1) {
System.out.println("in getAsynchTest: ExecutionException: " + e1);
ExceptionThrower.throwUnchecked(e1.getCause());
}
catch (TimeoutException e1) {
System.out.println("in getAsynchTest: TimeoutException: " + e1);
throw new TestApplicationTimeoutException("TimeoutException" + e1);
}
catch (InterruptedException e1) {
System.out.println("in getAsynchTest: InterruptedException: " + e1);
throw new Exception(e1);
}
return dummy;
}
}
See also this post The approach is let your application care of timeout inside its logic. For that you can define some timer class and special checking method, e.g.:
public class TimeoutApp {
MyTimer timer;
Thread timerThread;
public static void main(String... args) {
new TimeoutApp().execute();
}
private void execute() {
try {
startTimer(1000);
action1();
checkTimeout();
action2();
checkTimeout();
action3();
stopTimer();
} catch (MyTimeoutException e) {
System.out.println("Interrupted on timeout!");
// ...clearing code if needed
System.exit(1);
} catch (InterruptedException e) {
System.out.println("Interrupted by exception!");
// ...clearing code if needed
e.printStackTrace();
System.exit(1);
}
}
private void action1() throws InterruptedException {
Thread.sleep(600);
System.out.println("action 1");
}
private void action2() throws InterruptedException {
Thread.sleep(500);
System.out.println("action 2");
}
private void action3() {
System.out.println("action 3");
}
private void checkTimeout() throws MyTimeoutException {
if (timer.isTimeoutReached()) {
throw new MyTimeoutException();
}
}
private void startTimer(long timeout) {
timer = new MyTimer(timeout);
timerThread = new Thread(timer);
timerThread.start();
}
private void stopTimer() {
timerThread.interrupt();
}
private class MyTimer implements Runnable {
private long timeout;
private boolean timeoutReached = false;
public MyTimer(long timeout) {
this.timeout = timeout;
}
public void run() {
long time = System.currentTimeMillis();
while (!timeoutReached && !Thread.interrupted()) {
if ((System.currentTimeMillis() - time) > timeout) {
timeoutReached = true;
}
}
}
public boolean isTimeoutReached() {
return timeoutReached;
}
}
private class MyTimeoutException extends Exception {
}
}
I'm computing a future for having a timeout in waiting for a serial event to happen:
Future<Response> future = executor.submit(new CommunicationTask(this, request));
response = new Response("timeout");
try {
response = future.get(timeoutMilliseconds, TimeUnit.MILLISECONDS);
} catch (InterruptedException | TimeoutException e) {
future.cancel(true);
log.info("Execution time out." + e);
} catch (ExecutionException e) {
future.cancel(true);
log.error("Encountered problem communicating with device: " + e);
}
The CommunicationTask class has implemented the Observer interface to listen to an change from the serial port.
The problem is that reading from the serial port is relatively slow and even when a serial event is happening the time runs out and a TimeoutException is thrown. What can I do to stop the timeout clock of my future when a serial event is happening?
I tried it with an AtomicReference but that didn't change anything:
public class CommunicationTask implements Callable<Response>, Observer {
private AtomicReference atomicResponse = new AtomicReference(new Response("timeout"));
private CountDownLatch latch = new CountDownLatch(1);
private SerialPort port;
CommunicationTask(SerialCommunicator communicator, Request request) {
this.communicator = communicator;
this.message = request.serialize();
this.port = communicator.getPort();
}
#Override
public Response call() throws Exception {
return query(message);
}
public Response query(String message) {
communicator.getListener().addObserver(this);
message = message + "\r\n";
try {
port.writeString(message);
} catch (Exception e) {
log.warn("Could not write to port: " + e);
communicator.disconnect();
}
try {
latch.await();
} catch (InterruptedException e) {
log.info("Execution time out.");
}
communicator.getListener().deleteObserver(this);
return (Response)atomicResponse.get();
}
#Override
public void update(Observable o, Object arg) {
atomicResponse.set((Response)arg);
latch.countDown();
}
}
What can I do to solve this problem?
EDIT:
Ok I had one error. I was counting down my latch befor setting the atomicResponse in my update function. Now it seems to work, but there's still the question if this approach is the right way to do so?
have you explored google's Guava 'future listener', it is based on Async future, hope following code snippet helps you....
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
public class SyncFutureExample {
public static void main(String[] args) {
ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(1));
ListenableFuture<String> lf = service.submit(new CommuncationTask());
//no need for future.get() or future.get(10,time minutes)
//add callbacks(= async future listeners) ....
Futures.addCallback(lf, new FutureCallback<String>() {
public void onSuccess(String input) {
System.out.println(input + " >>> success");//gets a callback once task is success
}
public void onFailure(Throwable thrown) {
System.out.println(thrown + " >>> failure");//gets a callback if task is failed
}
});
service.shutdown();
}
}
class CommuncationTask implements Callable<String>{
public String call() throws Exception {
TimeUnit.SECONDS.sleep(15);// some dummy serious task .............
return "TaskDone";
}
}
Hope this will help. I won't comment on it in the hopes that everything is clear from the code.
class CommunicationTask implements Callable<String>, Observer {
volatile boolean ignoreTimeoutException;
public CommunicationTask(SerialCommunicator communicator, Request request) {
}
public String call() throws Exception {
Thread.sleep(1000);
return "done";
}
public void update(Observable o, Object arg) {
ignoreTimeoutException = true;
}
}
class FutureCommunicationTask extends FutureTask<String> {
private CommunicationTask ct;
public FutureCommunicationTask(CommunicationTask ct) {
super(ct);
this.ct = ct;
}
public String get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
try {
return super.get(timeout, unit);
} catch (TimeoutException e) {
if (ct.ignoreTimeoutException) {
return get(); // no timeout wait
}
throw e;
}
}
}
public class Test {
public static void main(String[] args) throws Exception {
CommunicationTask ct = new CommunicationTask(null, null);
FutureTask<String> fct = new FutureCommunicationTask(ct);
ExecutorService ex = Executors.newSingleThreadExecutor();
ex.execute(fct);
// uncomment this line and timeout will be cancelled
ct.update(null, null);
String res = fct.get(1, TimeUnit.MILLISECONDS);
System.out.println(res);
}
}
I'm using a third party Java library to interact with a REST API. The REST API can sometimes take a long time to respond, eventually resulting in a java.net.ConnectException being thrown.
I'd like to shorten the timeout period but have no means of modifying the third party library.
I'd like to apply some form of timeout control around the calling of a Java method so that I can determine at what point to give up waiting.
This doesn't relate directly to network timeouts. I'd like to be able to try and perform an operation and be able to give up after a specified wait time.
The following is by no means valid Java but does conceptually demonstrate what I'd like to achieve:
try {
Entity entity = new Entity();
entity.methodThatMakesUseOfRestApi();
} catch (<it's been ages now, I don't want to wait any longer>) {
throw TimeoutException();
}
I recommend TimeLimiter from Google Guava library.
This is probably the current way how this should be done with plain Java:
public String getResult(final RESTService restService, String url) throws TimeoutException {
// should be a field, not a local variable
ExecutorService threadPool = Executors.newCachedThreadPool();
// Java 8:
Callable<String> callable = () -> restService.getResult(url);
// Java 7:
// Callable<String> callable = new Callable<String>() {
// #Override
// public String call() throws Exception {
// return restService.getResult(url);
// }
// };
Future<String> future = threadPool.submit(callable);
try {
// throws a TimeoutException after 1000 ms
return future.get(1000, TimeUnit.MILLISECONDS);
} catch (ExecutionException e) {
throw new RuntimeException(e.getCause());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new TimeoutException();
}
}
There is no general timeout mechanism valid for arbitrary operations.
While... there is one... by using Thread.stop(Throwable). It works and it's thread safe, but your personal safety is in danger when the angry mob confronts you.
// realizable
try
{
setTimeout(1s); // 1
... any code // 2
cancelTimeout(); // 3
}
catch(TimeoutException te)
{
// if (3) isn't executed within 1s after (1)
// we'll get this exception
}
Now we have our nice CompletableFuture , here an application to achieve what was asked.
CompletableFuture.supplyAsync(this::foo).get(15, TimeUnit.SECONDS)
You could use a Timer and a TimerTask.
Here's a utility class I wrote, which should do the trick unless I've missed something. Unfortunately it can only return generic Objects and throw generic Exceptions. Others may have better ideas on how to achieve this.
public abstract class TimeoutOperation {
long timeOut = -1;
String name = "Timeout Operation";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getTimeOut() {
return timeOut;
}
public void setTimeOut(long timeOut) {
this.timeOut = timeOut;
}
public TimeoutOperation (String name, long timeout) {
this.timeOut = timeout;
}
private Throwable throwable;
private Object result;
private long startTime;
public Object run () throws TimeoutException, Exception {
Thread operationThread = new Thread (getName()) {
public void run () {
try {
result = doOperation();
} catch (Exception ex) {
throwable = ex;
} catch (Throwable uncaught) {
throwable = uncaught;
}
synchronized (TimeoutOperation.this) {
TimeoutOperation.this.notifyAll();
}
}
public synchronized void start() {
super.start();
}
};
operationThread.start();
startTime = System.currentTimeMillis();
synchronized (this) {
while (operationThread.isAlive() && (getTimeOut() == -1 || System.currentTimeMillis() < startTime + getTimeOut())) {
try {
wait (1000L);
} catch (InterruptedException ex) {}
}
}
if (throwable != null) {
if (throwable instanceof Exception) {
throw (Exception) throwable;
} else if (throwable instanceof Error) {
throw (Error) throwable;
}
}
if (result != null) {
return result;
}
if (System.currentTimeMillis() > startTime + getTimeOut()) {
throw new TimeoutException("Operation '"+getName()+"' timed out after "+getTimeOut()+" ms");
} else {
throw new Exception ("No result, no exception, and no timeout!");
}
}
public abstract Object doOperation () throws Exception;
public static void main (String [] args) throws Throwable {
Object o = new TimeoutOperation("Test timeout", 4900) {
public Object doOperation() throws Exception {
try {
Thread.sleep (5000L);
} catch (InterruptedException ex) {}
return "OK";
}
}.run();
System.out.println(o);
}
}
static final int NUM_TRIES =4;
int tried =0;
boolean result =false;
while (tried < NUM_TRIES && !result)
{
try {
Entity entity = new Entity();
result = entity.methodThatMakesUseOfRestApi();
}
catch (<it's been ages now, I don't want to wait any longer>) {
if ( tried == NUM_TRIES)
{
throw new TimeoutException();
}
}
tried++;
Thread.sleep(4000);
}
What should I use to get semantics equivalent to AutoResetEvent in Java?
(See this question for ManualResetEvent).
#user249654's answer looked promising. I added some unit tests to verify it, and indeed it works as expected.
I also added an overload of waitOne that takes a timeout.
The code is here in case anyone else finds it useful:
Unit 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);
}
}
AutoResetEvent with overload that accepts a 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;
}
}
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;
}
}
I was able to get CyclicBarrier to work for my purposes.
Here is the C# code I was trying to reproduce in Java (it's just a demonstration program I wrote to isolate the paradigm, I now use it in C# programs I write to generate video in real time, to provide accurate control of the 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");
}
}
}
}
and here is the Java code I came up with to do the same thing (using the CyclicBarrier class as suggested in a previous answer):
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");
}
}
}
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();
}
}
}
One more extension to the solution from the accepted answer in case you would like to know whether your wait finished with timeout or with event set (which is exactly what .NET AutoResetEvent does).
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;
}
}
}
I believe what you're looking for is either a CyclicBarrier or a CountDownLatch.