异步for循环没有挂起

时间:2018-04-05 21:21:00

标签: java multithreading loops asynchronous

我写了一个这样的同步for循环:

for (Map.Entry<String, CustomClass> entry : assocs.entrySet()) {
  String key = entry.getKey();
  CustomClass value = entry.getValue();
  value.tick(key);
}

问题是有时(很少).tick会挂起。如果单个.tick,没什么大不了的,它会在一段时间后自行修复并且实际上并不重要(这是由于互联网速度慢的客户端)。但是,如果它延迟了其余的那么,那就是一个问题。

所以我希望每个循环体都能运行而不必等待其他循环体完成。

3 个答案:

答案 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())));