我有一个要求,在单个方法调用中,我想要三个不同的集合来检索数据。现在我正在做一个接一个的数据。相反,我想创建三个线程,每个线程应并行执行。然后在完成每件事后,我想合并结果并将其发送给客户。
public List<String> getUserData() {
// all the tasks should execute in parallel & finally
// merge all the result & send to the client.
task1();
task2();
task3();
}
任何人都可以帮我解决问题吗?
答案 0 :(得分:0)
将相同的CyclicBarrier传递给所有线程。
// you have 3 threads,
CyclicBarrier meetingPoint=new CyclicBarrier(3);
// assigns their "barrier" variable to cyclic barrier
YourThreadGenerator thread1=new YourThreadGenerator(meetingPoint);
YourThreadGenerator thread2=new YourThreadGenerator(meetingPoint);
YourThreadGenerator thread3=new YourThreadGenerator(meetingPoint);
然后在三个线程中的每个线程中
this.barrier.await();
这确保所有线程都等待,直到所有其他线程(具有相同的循环屏障指令)都到达此行,然后程序流继续为它们执行,并且它们可以重复此过程。
你甚至不需要显式同步。但这对很多线程来说都很慢。如果你有几个线程,那就ok。
为了更容易,您可以将主线程计为第4个线程并调用
meetingPoint.await();
在里面。但它需要用1个额外的线程实例化
CyclicBarrier meetingPoint=new CyclicBarrier(4);
答案 1 :(得分:0)
ExecutorService
为通用并行处理提供强大的高级支持。在这里,我假设您的任务是由返回记录的某个服务(task1()
)提供的不同方法(task2()
,svc
,...),结果是这些结果的并集
void getUserData1()
throws InterruptedException, ExecutionException, CancellationException
{
List<Callable<List<String>>> tasks = Arrays.asList(svc::task1, svc::task2, svc::task3);
ExecutorService workers = Executors.newFixedThreadPool(tasks.size());
List<Future<List<String>>> tickets;
try {
tickets = workers.invokeAll(tasks, 10, TimeUnit.SECONDS);
}
finally {
workers.shutdown();
}
List<String> results = new ArrayList<>();
for (Future<List<String>> ticket : tickets)
results.addAll(ticket.get());
}
需要处理例外情况;在这里,我指定一个10秒的超时。如果在那段时间内没有准备好某些结果,则抛出CancellationException
。如果另一个线程通过中断此线程取消此请求,则抛出InterruptedException
,如果任务失败,则抛出ExecutionException
。在所有这些情况下,您可能会以相同的方式回复客户端,并显示“内部错误”消息。
在此示例中,ExecutorService
随每个请求一起创建和销毁,这是昂贵的。在具有明确定义的生命周期的应用程序中,定义何时可以创建和销毁服务,可以将其重用于所有请求。在这种情况下,您可能需要cached thread pool而不是固定的线程池。
也可以使用较新的ForkJoinPool
或基于fork-join构建的parallel Stream
功能,但它适用于较窄的任务集。如果任务没有阻止或抛出已检查的异常,Stream
是简明扼要的。如果任务耗时但可以轻松地递归细分为较小的任务,ForkJoinPool
可能值得使用。以下是使用Stream
:
List<String> getUserData2()
{
Stream<Supplier<List<String>>> s = Stream.of(svc::task1, svc::task2, svc::task3);
return s.parallel().map(Supplier::get).flatMap(List::stream).collect(Collectors.toList());
}