The ultimate structure seems much the same: start off a worker, and then you wait for the result with a timeout. As an example, the following code gives the same result:
In Go:
c := make(chan Result)
go func() { c <- Web(query) } ()
go func() { c <- Image(query) } ()
go func() { c <- Video(query) } ()
for i := 0; i < 3; i++ {
result := <-c
results = append(results, result)
}
In Java: ExecutorService executorService = Executors.newCachedThreadPool();
Future[] futures = new Future[]{
executorService.submit(new Web(query)),
executorService.submit(new Image(query)),
executorService.submit(new Video(query)),
};
for (int i = 0; i < 3; i++) {
Result result = futures[i].get();
results.add(result);
}