我正在开发一个需要并行定期检查多个资源的程序:
public class JobRunner {
private final SensorService sensorService;
private ScheduledExecutorService executor = Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors());
public void run() {
sensorService.finalAll().forEach(sensor -> {
Runnable task = () -> {
// read and save new data to log
List<Double> data = sensor.fetchNewData();
this.save(data);
};
// execute every 10 sec
executor.scheduleWithFixedDelay(task, 0, 10, TimeUnit.SECONDS);
});
}
public void save(List<Double> data) {
// ...
}
}
findAll
调用返回大约50个传感器的列表,但是当我运行程序时,我看到虽然在第一个周期内查询了所有传感器,但在后续执行时只调用了2-3个(例如 - 20秒,30秒等)。我认为,由于某些传感器的返回速度比其他传感器快,因此它们可以提前完成任务的等待周期,并被池中的下一个线程抓住,从而使其他任务更快完成。
如何确保所有任务(传感器)得到平等对待?这里有一些最好的做法;我应该使用作业队列还是不同的并发机制?感谢。
答案 0 :(得分:1)
在您的代码中有N=count service.findAll()
个计时器,这使得调试和测试更加困难。此外,无法保证在合理的时间内执行旧任务并且不会被新任务超越。怎么样?
请以下一个代码为例。它每10秒打印50个整数,然后EOL打印。使用Stream API
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
executor.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
IntStream.range(0, 50).parallel().forEach(i -> System.out.print(i + " "));
System.out.println();
}
}, 0, 10, TimeUnit.SECONDS);
您可以将ScheduledExecutorService
替换为Timer
,以使代码更清晰。而且,作为一种选择,您可以使用另一个ExecutorService
,而不是使用并行流,在N
上向其提交下一个Timer
任务,并等待它们完成:
ExecutorService workerExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
List<Future<Void>> futures = new ArrayList<>();
for (int i = 0; i < 50; i++) {
final int index = i;
Future<Void> future = workerExecutor.submit(new Callable<Void>() {
@Override
public Void call() throws Exception {
System.out.print(index + " ");
return null;
}
});
futures.add(future);
}
for (Future<Void> future : futures) {
try {
future.get();
} catch (InterruptedException|ExecutionException e) {
throw new RuntimeException();
}
}
System.out.println();
}
}, 0, 10_000);