I am working with an external lib that defines a Monitor
class that accepts a Sensor
interface and sends results into it periodically:
public interface Sensor {
// called by the monitor when new results are available
void updatedResult(double result);
// called when done sending results
void done();
}
I have implemented the sensor as follows:
public class SensorImpl implements Sensor {
private boolean isDone;
private List<double> data;
public SensorImpl() {
this.isDone = false;
this.data = new ArrayList<>();
}
@Override
void updatedResult(double result);
this.data.add(result);
}
@Override
void done() {
this.isDone = true;
}
public boolean isDoneReceiving() {
return this.isDone;
}
public List<double> getData() {
return this.data;
}
}
And am running my program like this (simplified):
public void run() {
// initialize a sensor instance
SensorImpl sensor = new SensorImpl();
// initialize a monitor that streams data into the sensor (async)
Monitor monitor = new Monitor(sensor);
// start monitoring the sensor
monitor.start();
// block until done
while (!sensor.isDoneReceiving()) {
Thread.sleep(50);
}
// retrieve data and continue processing...
List<double> data = sensor.getData();
// ...
}
While this works, it feels icky to be blocking on a thread with sleep, and I'm looking for a way to make this cleaner. This becomes even more relevant when applying executors to monitor multiple sensors of various types in parallel. Any assistance will be appreciated.
I ended up implementing Future<List<Double>>
, which allowed me to simply call List<Double> results = sensor.get();
, which blocks until all results are available.
public class SensorImpl implements Sensor {
// ...
private CountDownLatch countDownLatch;
public SensorImpl() {
this.countDownLatch = new CountDownLatch(1);
}
// ...
@Override
public void done() {
// when called by async processes, decrement the latch (and release it)
this.countDownLatch.countDown();
}
// ...
}
Here's a great answer that provided good reference: https://stackoverflow.com/a/2180534/187907
In your case, several classes from the concurrent
package can help you, such as Semaphore
, CoundDownLatch
, CyclicBarrier
or even a BlockingQueue
, where you would block on the queue and wait for the other threads to put values in it when finished.
A CountDownLatch is most probably best suited for your specific example. Perhaps you can view this question, it has a nice overview about Semaphore and CountDownLatch: