我写了一个这样的同步for循环:
for (Map.Entry<String, CustomClass> entry : assocs.entrySet()) {
String key = entry.getKey();
CustomClass value = entry.getValue();
value.tick(key);
}
问题是有时(很少).tick
会挂起。如果单个.tick
,没什么大不了的,它会在一段时间后自行修复并且实际上并不重要(这是由于互联网速度慢的客户端)。但是,如果它延迟了其余的那么,那就是一个问题。
所以我希望每个循环体都能运行而不必等待其他循环体完成。
答案 0 :(得分:3)
Andrew's solution几乎是正确的,因为它使用包含10个线程的固定线程池;如果assocs
中包含的元素超过10个,则第11个元素可能会停止,因为它将与其余元素一起争用一个线程。正确的方法是使用带有缓存线程池的ExecutorService
:
ExecutorService service = Executors.newCachedThreadPool();
assocs.entrySet().forEach(entry -> {
service.execute(() -> {
String key = entry.getKey();
CustomClass value = entry.getValue();
value.tick(key);
);
);
答案 1 :(得分:2)
创建ExecutorService实际上比手动管理自己的线程更简单:
final ExecutorService exec = Executors.newFixedThreadPool(10);
//create a list of Futures, so you know when each tick is done
final List<Future> futures = new ArrayList<>();
for (final Map.Entry<String, CustomClass> entry : assocs.entrySet()) {
final Future<?> future = exec.submit(new Runnable() {
public void run() {
String key = entry.getKey();
CustomClass value = entry.getValue();
value.tick(key);
}
});
futures.add(future);
}
// wait for each future to complete before moving on
for (final Future<?> future : futures) {
try {
future.get();
} catch (Execption e) {
e.printStackTrace();
}
}
我强烈建议您以多线程和单线程方式运行代码。除非value.tick
花费非常长时间,否则在一个线程中执行此操作可能会更快;每当运行多线程代码时,Java都必须执行大量无形的开销工作,以确保不会以不一致的方式访问内存。
答案 2 :(得分:2)
最简单的并行方法可能是使用并行流:
assocs.entrySet().parallelStream()
.forEach(e -> e.getValue().tick(e.getKey()));
但请注意,这将使用ForkJoinPool.commonPool
来执行您的线程,这比您拥有处理器的线程少一个。
如果要增加并行度,可以始终使用自己的ForkJoinPool运行
new ForkJoinPool(numberOfThreads).submit(() ->
assocs.entrySet().parallelStream()
.forEach(e -> e.getValue().tick(e.getKey())));