Is it possible to block/wait an already existing asynchronous function? - java

SomeLibrary lib = new SomeLibrary();
lib.doSomethingAsync(); // some function from a library I got and what it does is print 1-5 asynchronously
System.out.println("Done");
// output
// Done
// 1
// 2
// 3
// 4
// 5
I want to be clear that I didn't make the doSomethingAsync() function and it's out of my ability to change it. I want to find a way to block this async function and print Done after the numbers 1 to 5 because as you see Done is being instantly printed. Is there a way to do this in Java?

You can use CountDownLatch as follow:
final CountDownLatch wait = new CountDownLatch(1);
SomeLibrary lib = new SomeLibrary(wait);
lib.doSomethingAsync(); // some function from a library I got and what it does is print 1-5 asynchronously
//NOTE in the doSomethingAsync, you must call wait.countDown() before return
wait.await(); //-> it wait in here until wait.countDown() is called.
System.out.println("Done");
In Constructor SomeLibrary :
private CountDownLatch wait;
public ScannerTest(CountDownLatch _wait) {
this.wait = _wait;
}
In method doSomethingAsync():
public void doSomethingAsync(){
//TODO something
...
this.wait.countDown();
return;
}

This is achieved in a couple of ways in standard libraries :-
Completion Callback
Clients can often provider function to be invoked after the async task is complete. This function usually receives some information regarding the work done as it's input.
Future.get()
Async functions return Future for client synchronization. You can read more about them here.
Do check if any of these options are available (perhaps, an overloaded version ?_ in the method you wish to invoke. It is not too uncommon for libraries to include both sync and async version of some business logic so you could search for that too.

Related

Optimizing method with list of 500k+ elements

I'm looking for some help since I don't know how to optimize a process.
I have to invoke a service that returns a list with more than 500K elements (I don't know why, these services belongs to the client), per each element of the list, I have to invoke 2 more services and then save some attributes in our database, this last step is not the problem, but the entire process took between 1 and 2 seconds per element, so with this time is going to take like more of 100 hours to complete the process.
My approach is the following, I have my main method, inside this method I get the large list, then I use a parallelStream to iterate in the elements of the list and then I use a CompletableFuture to call the method that invokes the 2 services mentioned above. I've tried changing the parallelStream to stream and for-each , tried to split the main list into smaller lists and many other things but I don't see a better performance, I think the problem is the invocation of those 2 services but I want to try luck asking here.
I'm using java 11, spring, and for the invocation of the services I'm using RestTemplate, and this is my code:
public void updateDiscount() {
//List with 500k elements
var relationshipList = relationshipService.getLargeList();
//CompletableFuture to make the async calls to the method above
relationshipList.parallelStream().forEach(level1 -> {
CompletableFuture.runAsync(() -> relationshipService.asyncDiscountSave(level1));
});
}
//Second class
#Async("nameOfThePool")
public void asyncDiscountSave(ElementOfList element) {
//Logic to create request
//.........
var responseClients = anotherClass.getClients(element.getGroup1()) //get the first response with restTemplate
var responseProducts = anotherClass.getProducts(element.getGroup2())//get the second response with restTemplate
for (var client : responseClients) {
for (var product : responseProducts) {
//Here we just save some attributes of these objects on our DB
}
}
}
Thanks for the help.
UPDATE:
For this particular case, the only improvement that I can do is to pass a thread pool to the completable future, the problem is the response time of the services that I need to invoke.
I decided to follow a second approach and it took like 5 hours to complete, compared with the first approach this is acceptable.
As you haven't defined an executor you are using the default pool. Adding an executor allow you to create many threads as you needed and the server resources can manage
public void updateDiscount() {
Executor executor = Executors.newFixedThreadPool( 100 );//Define the number according to server resources performance
//List with 500k elements
var relationshipList = relationshipService.getLargeList();
//CompletableFuture to make the async calls to the method above
relationshipList.parallelStream().forEach(level1 -> {
CompletableFuture.runAsync(() -> relationshipService.asyncDiscountSave(level1), executor);
});
}

CompletionService vs CompletableFuture

I have 1000 big files to be processed in order as mentioned below:
First those files needs to be copied to a different directory in parallel, I am planning to use ExecutorService with 10 threads to achieve it.
As soon as any file is copied to another location(#1), I will submit that file for further processing to ExecutorService with 10 threads.
And finally, another action needs to be performed on these files in parallel, like #2 gets input from #1, #3 gets input from #2.
Now, I can use CompletionService here, so I can process the thread results from #1 to #2 and #2 to #3 in the order they are getting completed. CompletableFuture says we can chain asynchronous tasks together which sounds like something I can use in this case.
I am not sure if I should implement my solution with CompletableFuture (since it is relatively new and ought to be better) or if CompletionService is sufficient? And why should I chose one over another in this case?
It would probably be best if you tried both approaches and then choose the one you are more comfortable with. Though it sounds like CompletableFutures are better suited for this task because they make chaining processing steps / stages really easy. For example in your case the code could look like this:
ExecutorService copyingExecutor = ...
// Not clear from the requirements, but let's assume you have
// a separate executor for this
ExecutorService processingExecutor = ...
public CompletableFuture<MyResult> process(Path file) {
return CompletableFuture
.supplyAsync(
() -> {
// Retrieve destination path where file should be copied to
Path destination = ...
try {
Files.copy(file, destination);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
return destination;
},
copyingExecutor
)
.thenApplyAsync(
copiedFile -> {
// Process the copied file
...
},
processingExecutor
)
// This separate stage does not make much sense, so unless you have
// yet another executor for this or this stage is applied at a different
// location in your code, it should probably be merged with the
// previous stage
.thenApply(
previousResult -> {
// Process the previous result
...
}
);
}

Only start function when previous function has completed

I have 3 methods and they're being called from the front end. You can only call a function once you have called the previous function, but don't necessarily need to call all of them. So you may call either just f1, or f1->f2 or f1->f2->f3.
My problem is that on the front end you can click on a function, before the previous one has even stopped running. I need each function to finish before the next function starts running.
What I'm doing at the moment, which works, is pausing the execution until the end of the previous function, but I'd like for a nicer answer:
f1 {
ready1=false
...
ready1=true }
f2 {
ready2=false
while (!ready1) {Thread.sleep(250);}
...
ready2=true }
f3 {
while (!ready2) {Thread.sleep(250);}
...
}
Is there an easy way to do this?
It sounds like you're using a web framework, so maybe include the framework, and it will have some built in tools. One example is to use the built in java tools.
class NoLookingBack{
CountDownLatch latchB = new CountDownLatch(1);
public void methodA(){
//do work.
latchB.countDown();
}
public void methodB(){
try{
latchB.await();
} catch(InterruptException e){
//do something or declare this method throws.
return;
}
}
}
I think this shows how more methods could be included by adding more latches when necessary.
Your example is flawed, and so is this solution. What if methodA fails, then methodB will block forever. The latch gives you the power to use a timeout value, then you can use a response that indicates a failure.

Continue when one future task has expected result

I have 3 FutureTask<T> Objects. I want that they are processed asynchronously. However, as soon as one of the FutureTasks' get() methods doesn't return null I want to continue i.e my method (wrapper) returns and doesn't wait until the other two FutureTasks are processed.
I thought about something like:
private File wrapper(final File file) {
ExecutorService executors = Executors.newCachedThreadPool();
File returnFile;
FutureTask<File> normal= ...
FutureTask<File> medium=...
FutureTask<File> huge=...
executors.execute(normal);
executors.execute(medium);
executors.execute(huge);
try {
if((returnFile=normal.get()) != null ||
(returnFile=medium.get()) != null ||
(returnFile=huge.get()) != null)
return returnFile;
} catch(ExecutionException | InterruptedException e) { }
}
I'm not sure how to capture the exceptions (thrown by the get()) in a proper way because I assume they will be thrown since I just return without waiting for the other two tasks to be completed. Moreover I've doubts that the code will work like intended. I feel that I'm close to the solution but missing something.
May I suggest to check for FutureTask::isDone?
Would be something like this then:
while(true) {
if (normal.isDone()) {
return normal.get();
}
if (medium.isDone()) {
return medium.get();
}
if (huge.isDone()) {
return huge.get();
}
}
EDIT:
You could cancel the other tasks as soon as you have one result at hand.
Using FutureTask::get is not what you look for as it would most likely always return the result of normal.get() because the documentation already states that:
Waits if necessary for the computation to complete, and then retrieves
its result.
To clarify the above:
If you use FutureTask::get the first FutureTask you call get on will most likely block and wait until a result is available to return.
EDIT2:
Wrap that loop into a new Runnable, executed by the ExecutorService, passing the first result available to another method or implement a Callback and there's no more busy waiting.
I had an idea to design it using BlockingQueue. You extend your tasks with done method submitting results into BlockinQueue and, once client received first result, it cancels other tasks. On the other hand, experts suggest using ExecutorCompletionService instead. It seems to serialize results imself and has all appropriate examples.

Out-of-order returns from Java Futures

The only model that I can come up with for running multiple similar processes (SIMD) using
Java Futures (java.util.concurrent.Future<T>) is as follows:
class Job extends Callable<T> {
public T call() {
// ...
}
}
List<Job> jobs = // ...
List<Future<T>> futures = ExecutorService.invokeAll(jobs);
for (Future<T> future : futures) {
T t = future.get();
// Do something with t ...
}
The problem with this model is that if job 0 takes a long time to complete, but jobs 1, 2, and 3 have already completed, the for loop will wait to get the return value from job 0.
Is there any model that allows me to get each Future result as it becomes available without just calling Future.isDone() and busy waiting (or calling Thread.sleep()) if none are ready yet?
You can try out the ExecutorCompletionService:
http://download.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/ExecutorCompletionService.html
You would simply submit your tasks and call take until you've received all Futures.
Consider using ListenableFuture from Guava. They let you basically add a continuation to execute when the future has completed.
Why don't you add what you want done to the job?
class Job extends Runnable {
public void run() {
// ...
T result = ....
// do something with the result.
}
}
That way it will process the result as soon as it is available, concurrently. ;)
A CompletionService can be polled for available results.
If all you want is the results as they become available however, we wrote an AsyncCompleter that abstracts away the detail of completion service usage. It lets you submit an Iterable<Callable<T>> of jobs and returns an Iterable<T> of results that blocks on next() and returns the results in completion order.

Categories

Resources