我的多线程代码需要帮助。 我有一个可调用的类,它返回一个值。我有一个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,对吗?
答案 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
,它允许您在完成任务时处理这些任务,而不必按顺序等待它们。您可能要求输出顺序,在这种情况下这没有用,但无论如何都是很好的技术。