Reputation: 1033
I have a Person
that I am trying to populate. Many of the setter methods take time to populate since the data is supplied from DB calls that can take some time (over 10 seconds) to return.
I am looking for the best way to populate my mutators asynchronously before returning my Person
back to the calling method.
Here's an example:
Person p = service.getPersonById(id);
// populate from DMV DB
p.setTickets(dmvService.getTicketsById(id)); // takes 15 seconds to return data
p.setAccidentRecord(dmvService.getAccidentsById(id)); // takes 10 seconds.
...
...
return p;
I would like to be able to run my methods (setTickets
, setAccidentRecord
, etc) asynchronously to reduce my load time down from over 25 seconds to around 15.
Upvotes: 1
Views: 70
Reputation: 362037
CompletableFuture
†, introduced in Java 8, is just the ticket. It is a monadic, chainable class that makes it easy to manage off-thread computations.
A future represents a computation that will finish and yield a result some time in the future. It may have already completed, or it may take a while in some background thread. CompletableFuture
builds on this core concept by letting you attach all kinds of additional transformations and handlers to an existing future.
Person p = service.getPersonById(id);
CompletableFuture.allOf(
CompletableFuture.supplyAsync(() -> dmvService.getTicketsById(id))
.thenAccept(p::setTickets),
CompletableFuture.supplyAsync(() -> dmvService.getAccidentsById(id))
.thenAccept(p::setAccidentRecord)
).join();
return p;
In your case, you can use supplyAsync
to run getTicketsById
and getAccidentsById
in background threads. Since you want to call the corresponding setters when those methods return, you use thenAccept
to say, "when that method returns, supply the value to this setter".
You have two background computations and you don't want to return until both of them complete. Wrapping both of those futures into a bigger one with allOf
gets us there. The allOf
future doesn't itself complete until the two inner futures are both completed.
Finally, we join
the allOf
future, which waits for it to finish before proceeding. If any of this code might throw an exception then join
will throw that exception itself—although it'll be wrapped in a CompletionException
—so you can add a try/catch around it if you wish.
†Unfortunately, Java's first stab at this concept, Future
, is an underpowered, lackluster class. They got it right with CompletableFuture
, but Future
stole the ideal name.
Upvotes: 2