写作来自CachedThreadPool的Future。我的实施不正确吗?

时间:2017-11-14 13:41:34

标签: java multithreading executorservice callable

我的多线程代码需要帮助。 我有一个可调用的类,它返回一个值。我有一个cachedThreadPool来提交~60,000个任务。我收集列表中的所有期货。在ExecutiveService关闭后,我遍历Futures列表,并使用bufferedWriter写入返回的值。这是正确的实施方式吗?

ExecutorService execService = Executors.newCachedThreadPool();
List<Future<ValidationDataObject<String, Boolean>>> futureList = new ArrayList<>();
for (int i = 0; i < emailArrayList.size(); i++) {
    String emailAddress = emailArrayList.get(i);
    ValidateEmail validateEmail = new ValidateEmail(emailAddress);
    Future<ValidationDataObject<String, Boolean>> future = 
         execService.submit(validateEmail);
    futureList.add(future);
}

execService.shutdown();

for (Future<ValidationDataObject<String, Boolean>> future: futureList) {
    ValidationDataObject<String, Boolean> validationObject = future.get();
    bufferedWriter.write(validationObject.getEmailAddress() + "|"
             + validationObject.getIsValid());
    bufferedWriter.newLine();
    bufferedWriter.flush();
}

if (execService.isTerminated()) bufferedWriter.close();

我应该为bufferedWriter使用synchronized块吗?我在想,它不需要同步,因为我正在使用主线程中的bufferedWriter,对吗?

2 个答案:

答案 0 :(得分:0)

除了事实,executor.shutdown()很可能不会做,你认为它做什么(它只是阻止Executor接受新任务,它不会等待所有任务终止),你的代码看起来很好。

你是对的,不需要与编写器同步,因为你只访问单线程。

但有些事情可以改进。首先,您没有进行大量的异常处理。如果Future.get()点击ExecutionException,则Callable会抛出Exception

我不确定,Callables的执行时间偏差有多大。假设,以下情况有明显的偏差:假设我们提交{A},A和B,您收到FutA,FutB和FutC。调用Callable方法将一直阻塞,直到get后面的计算完成。在您的设置中,您可能正在等待FutA完成,而FutB / FutC可能已经完成并准备好写作。最糟糕的情况是,处理A会延迟所有60000任务的写入。

我想,我会采用另一种方法,每个Future获取对同一Callable的引用,而不是通过ConcurrentLinkedQueue返回结果将结果写入该队列。在这种情况下,结果的排序不依赖于Future的排序,而是在时间上Callable完成执行。这是否会导致加速取决于您的设置(特别是写入结果的时间和Callable s执行时间的偏差)。

答案 1 :(得分:0)

  

我有一个cachedThreadPool来提交~60,000个任务。

关闭蝙蝠,缓存的线程池和60k任务是一个红旗。这将启动6k线程,我怀疑你真的想要。您应该使用固定的线程池并改变线程数,直到您实现吞吐量与压倒性服务器之间的良好平衡。也许从CPU数量的2倍开始,然后根据服务器负载改变它。

您可能也会考虑使用固定大小的队列,这会限制未完成的任务数量,尽管60k任务很好,除非这些对象很重。

  

我收集列表中的所有期货。在ExecutiveService关闭后,我遍历Futures列表,并使用bufferedWriter写入返回的值。这是正确的实施方式吗?

是的,这是一个很好的模式。你没有显示正在创建的编写器,但主线程拥有它肯定是好的。

  

我应该为bufferedWriter使用synchronized块吗?我在想,它不需要同步,因为我正在使用主线程中的bufferedWriter,对吗?

右。没有其他线程正在使用它,所以没关系。这是一个非常典型的模式,让编写器线程管理多线程应用程序的输出。

最后一条评论是,您可能希望查看ExecutionCompletionService,它允许您在完成任务时处理这些任务,而不必按顺序等待它们。您可能要求输出顺序,在这种情况下这没有用,但无论如何都是很好的技术。