Use ExecutorCompletionService to perform concurrent calls to different dependencies - java

I am trying to use the ExecutorCompletionService - https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorCompletionService.html, to try and perform concurrent calls to two different dependent packages.
The reason I am using ExecutorCompletionService is because I want to compare the results returned by both the dependencies and then emit a metric based on a specific requirement.
My code looks like this:
#Builder
#Slf4j
public class TestClass {
#NonNull private final ExecutorService threadPool = Executors.newFixedThreadPool(2);
#NonNull private final ExecutorCompletionService<ResultStructure1> dependency1Thread = new ExecutorCompletionService<>(threadPool);
#NonNull private final ExecutorCompletionService<ResultStructure2> dependency2Thread = new ExecutorCompletionService<>(threadPool);
public void myMethod() {
RequestObject1 firstDependencyRequest = RequestObject1.builder()
.attribute1("someValue")
.attribute2("secondValue");
RequestObject2 secondDepdencyRequest = RequestObject1.builder()
.attribute1("depdency2Value")
.attribute2("depdency2Secondvalue");
dependency1Thread.submit(() -> dependency1Client1.call(firstDependencyRequest));
dependency2Thread.submit(() -> dependencyClient2.call(secondDepdencyRequest));
final Future<ResultStructure1> future1 = dependency1Thread.take();
final Future<ResultStructure2> future2 = dependency2Thread.take();
try {
ResultStructure1 = future1.get();
ResultStructure2 = future2.get();
} catch (ExecutionException e) {
log.error("Exception calling dependency", e);
throw e;
}
}
}
Is this the correct way to be using ExecutorCompletionService for different dependencies? Is there a way to have a single executorService and have both the dependencies be called from that?

Is this the correct way to be using ExecutorCompletionService for
different dependencies?
Unfortunately, no. You'd typically use it to execute tasks returning similar type of results while you wait for their execution and their results to be available. Internally it uses a BlockingQueue where it adds the Futures as the tasks complete, which is then returned by its blocking take method.
So, if you do want to use an ExecutorCompletionService, you'd have to come up with a base/common type for ResultStructure1 and ResultStructure2 (i.e., ResultStructure), and declare a completion service like below -
private final ExecutorCompletionService<ResultStructure> completionService =
new ExecutorCompletionService<>(threadPool)
and then -
completionService.submit(() -> dependency1Client1.call(firstDependencyRequest));
completionService.submit(() -> dependencyClient2.call(secondDepdencyRequest));
You can then wait for their results to be available using the blocking take method -
Future<ResultStructure> result1 = completionService.take();
Future<ResultStructure> result2 = completionService.take();
Please note that at this point, we have no way of finding out which Future represents which concrete result type. So you have no way of comparing the results.
My recommendation would be to simply use ExecutorService directly.

Related

Best way to use Future in java

I have a set of jobs which I am submitting using executor framework and Future. Let's say that I have 100 futures. As of now, I am using Future.get and using the output for subsequent processing. However for further tuning, I want to change the flow as below:
iterate through the set of future tasks and start consuming the result as soon as a future task is complete. I am reading the API doc to understand what might be a good way to accomplish this but reaching out to see if there is a better way to accomplish what I am looking for.
Here is the sample code:
public class ImplCallable implements Callable<String> {
int timeOut;
ImplCallable(int timeOut) {
this.timeOut=timeOut;
}
public String call() throws Exception {
Thread.sleep(timeOut);
return Thread.currentThread().getName();
}
}
and the main class:
public class MainProg {
public static void main(String...args) throws Exception {
long startTimeInMillis = System.currentTimeMillis();
ImplCallable callable1 = new ImplCallable(1000);
ImplCallable callable2 = new ImplCallable(2000);
ExecutorService service = Executors.newFixedThreadPool(4);
Future<String> task1 = service.submit(callable1);
Future<String> task2 = service.submit(callable2);
List<Future<String>> futureList = new ArrayList();
futureList.add(task1);
futureList.add(task2);
String retVal;
for(Future<String> task:futureList) {
retVal = task.get();
//do something with the retVal
}
long endTimeInMillis = System.currentTimeMillis();
System.out.println("time taken by code - " + (endTimeInMillis-startTimeInMillis) + "-ms");
}
}
Basically I don't want to use Future.get() and wait for its completion. I want to know if either of the task is complete and use the result as soon as its done.
There are many ways do this so, without a concrete example, you won't get a concrete answer. Likely want to look at CompletableFuture which has many methods for defining follow-on work, combining work, splitting work etc.
Future<String> f = CompletableFuture.supplyAsync(() -> "INITIAL WORK")
.thenApply(String::toLowerCase) // Do some more work
.thenAccept(queue::add); // put results onto a queue something is reading from
f.join();
// Batch complete
I hope you are using Java 8 or later version.
Whenever you mention "as soon as a future task is complete", you want to use CompletableFuture and its .thenApply() method, as #drekbour suggests.
Then you have multiple threads running different tasks in non-determenistic sequence. But at the end you want to get all the results in the single (Main) thread. To achieve it, you can use CompletableFuture.allOf method, .join() it - and then iterate over all the (already completed) future results without waiting.

How to know if a Future is created with Callable or Runnable

I am dipping my feet in Futures. A Future can be created with a Runnable and with a Callable. Is there a way to decide how it was created?
For example, I have the following code:
Future<?> future = null;
Future<?> future2 = null;
ExecutorService service = null;
service = Executors.newSingleThreadExecutor();
future = service.submit(() -> {
for (int i = 0; i < 5; ++i) {
System.out.println("Printing record: " + i);
Thread.sleep(5);
}
return "Done";
});
future2 = service.submit(() -> System.out.println("Printing zoo inventory"));
System.out.println("================================================================");
System.out.println(future);
System.out.println(future.get().getClass());
System.out.println(future.get());
System.out.println("================================================================");
System.out.println(future2);
try {
System.out.println(future2.get().getClass());
System.out.println(future2.get());
} catch (ExecutionException e) {
System.out.println("Could not do a get");
}
System.out.println("================================================================");
This results in ending with:
================================================================
java.util.concurrent.FutureTask#5caf905d[Completed normally]
class java.lang.String
Done
================================================================
java.util.concurrent.FutureTask#1f32e575[Completed normally]
Exception in thread "main" java.lang.NullPointerException
at ZooInfo.main(ZooInfo.java:56)
I could solve this by using:
if (future2.get() == null) {
System.out.println("Made with a Runnable");
} else {
System.out.println(future2.get().getClass());
System.out.println(future2.get());
}
The problem with this is that when the Runnable still takes some time, I am waiting on the get for nothing. Is there a way to determine if a Future was created with a Runnable, or a Callable without resorting to using get()?
I don't believe that you really need to know whether the Future was created from a Runnable or a Callable.
For one thing, there are more ways than that to create a Future: for example, CompleteableFuture is not created from either; and, more generally, since Future is an interface, one can create instances however you like.
For another: the abstraction of Future is that it is something that gives you a (possibly null) value when it completes, or throws an exception. That's all it is meant to do.
(Also, your current approach of checking for nullity of the return value doesn't work reliably because Callable.call() is allowed to return null).
If you need it to do something else, you may want to revisit your design so you can simply treat it as it is intended.
But if you really do have a use case that does require you to know how it was created, you need to control the creation. Rather than letting callers submit code directly to the executor, wrap in a class like this:
class YourExecutor {
// Initialize in ctor.
private final ExecutorService executor;
FromRunnable submit(Runnable r) {
return new FromRunnable(executor.submit(r));
}
<T> FromCallable<T> submit(Callable<? extends T> c) {
return new FromCallable<>(executor.submit(c));
}
}
where FromRunnable and FromCallable<T> are classes implementing Future<Void> and Future<T> respectively, which delegate all of the methods to another instance of a compatible Future (passed as the constructor parameter).
You can then check the provenance using instanceof; or by some other means, such as extending a common base case or interface which provides a method describing the provenance.
But, just to reiterate, a better approach is to design your code so it doesn't need to know.

Do I need to control the execution of these two threads with the main threads?

void process(String question){
Callable<ResponseList> callable1 = () -> this.stsCompute question);
Future<ResponseList>task1 = executorService.submit(callable1);
Callable<ResponseList> callable2 = () -> this.dssmCompute(question);
Future<ResponseList>task2 = executorService.submit(callable2);
try{
ResponseList stsResponse = task1.get();
ResponseList dssmResponse = task2.get();
}catch (Exception e){
e.printStackTrace();
}
// Do I need to wait until the first 2 threads complete?
processResponse(stsResponse, dssmResponse);
}
In this "process" method, I have two additional threads 'callable1' & 'callable2' to concurrently execute. I want to make sure only when these two tasks complete, the method in the main thread 'processResponse()' can start to be executed.
In such a case, do I need to add any additional control to ensure the order of the execution, is it already good enough? If not, how to make that control happen?
You should use ExecutorService.invokeAll which will return List of Futures when complete. Besides I would use a shorter syntax, something like
List<Future> futures = executorService.invokeAll(Arrays.asList(()->dssmCompute(), ()->dssmCompute()));
With Java8+ i would suggest use Completable Futures. It supports exactly the use case you are trying to achieve.
Completable Futures: Java 8
Sample Algorithm looks like:
var cf = CompletableFuture.supplyAsync(() -> processQuestion()).runAsync(() -> processResponse)
Note: var is typeInference supports in java 10+
Also, there are plenty of Examples on Completable Futures

JavaFX Task Callable

I was developing a JavaFX app and I was supplying the JavaFX tasks in an ExecutorService submit method. Also I was trying to get the return value of the Task in the return value of the submit in a Future object. Then I discovered that ExecutorService only returns value when you submit a Callable object, and JavaFX Tasks are runnables despite having a call method. so is there any workaround for this problem?
I tried and solved my problem this way but I'm open to suggestions when I don't want to write my own class.
My main method:
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Semaphore semaphore = new Semaphore(1);
List<Integer> list = IntStream.range(0,100).boxed().collect(Collectors.toList());
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()){
List<Integer> sendingList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
sendingList.add(iterator.next());
}
System.out.println("SUBMITTING");
Future<Integer> future = executorService.submit((Callable<Integer>) new TestCallable(sendingList,semaphore));
System.out.println(future.get());
semaphore.acquire();
}
executorService.shutdown();
System.out.println("COMPLETED");
}
My TestCallable class:
class TestCallable extends Task<Integer> implements Callable<Integer> {
private Random random = new Random();
private List<Integer> list;
private Semaphore semaphore;
TestCallable(List<Integer> list, Semaphore semaphore) {
this.list = list;
this.semaphore = semaphore;
}
#Override
public Integer call(){
System.out.println("SENDING");
System.out.println(list);
try {
Thread.sleep(1000+random.nextInt(500));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("RECEIVED");
semaphore.release();
return list.size();
}
}
Task extends java.util.concurrent.FutureTask which in turn implements the Future interface. This means you can use a Task just like a Future.
Executor executor = ...;
Task<?> task = ...;
executor.execute(task);
task.get(); // Future method
This will cause the thread calling get() to wait until completion. However, a Task's purpose is to communicate the progress of a background process with the JavaFX Application Thread. It's close relationship to the GUI means you will most likely be launching a Task from the FX thread. This will lead to get() being called on the FX thread which is not what you want as it will freeze the GUI until get() returns; you might as well have just called Task.run directly.
Instead, you should be using the asynchronous functionality provided by Task. If you want to retrieve the value when the Task completes successfully you can use the onSucceeded property or listen to the value/state property. There's also ways to listen for failure/cancellation.
Executor executor = ...;
Task<?> task = ...;
task.setOnSucceeded(event -> handleResult(task.getValue()));
task.setOnFailed(event -> handleException(task.getException()));
executor.execute(task);
If you don't need the functionality provided by Task then it would probably be best to simply use Runnable or Callable directly.
It's not very clear what you want to do here.
Firstly, your Semaphore does nothing because you used Executors.newSingleThreadExecutor(), which already guarantees that only one task can run at any point in time.
Secondly, like what #Slaw mentioned, you are potentially blocking on JavaFX Application thread, depending on your actual implementation (your example isn't really a JavaFX application).
Next, ExecutorService has 2 main overloads for submit().
The first overload takes in a Callable. This overload allows you to retrieve the value returned by the Callable (by calling get() on the returned Future), because Callable refers to something that is can be called - it can return value.
The second overload takes in a Runnable. Since Task implements Future RunnableFuture interface, and Future RunnableFuture interface extends Runnable interface, passing in a Task would be equivalent to calling this overload. This overload does not expect a result to be returned, because Runnable is something that you run without a result. Calling get() on the Future returned by this overload will block until the task finishes, and null will be returned. If you need to retrieve the value returned by the Task, you need to call get() of the Task, not the Future returned by ExecutorService.submit().
Edit based on OP's comments
Firstly, since the calling method is already running in a background thread, and all tasks are expected to run sequentially (instead of parallelly), then you should just run them without all these additional ExecutorService and Task, unless there is another reason why this has to be done.
Secondly, a List object is nothing but an object doing referencing. What could have really affected performance is that you are copying the reference of the elements to the new list. You could have used List.subList()if the indices are known, as the returned list would use the same backing array as the original list, so there isn't an additional O(n) operation for copying.

How to instantiate Object or call setter to pass values from different Threads using java8 Labmdas and thread pool?

I have such old-style code:
ObjectToInstantiate instance = new ObjectToInstantiate();
Thread getFirstValueThread = new Thread(() -> instance.setFirstValue(service.getFirstValue));
Thread getSecondValueThread = new Thread(() -> instance.setSecondValue(service.getSecondValue));
getFirstValueThread.start();
getSecondValueThread.start();
try {
getFirstValueThread.join();
getSecondValueThread.join();
} catch (InterruptedException e) {
throw new RuntimeException(e.getMessage(), e);
}
return instance;
FirstValue and SecondValue are diffent classes, also I can pass them into constructor, not only setters.
How may i do this using ExecutorService or something else to avoid new thread creation?
Have a look at CompletableFutures which are designed with the idea of returning values after a given period of time. You can also easily manage the Exception cases as well.
CompletableFuture<FirstValue> f1 = CompletableFuture.supplyAsync(() -> service.getFirstValue());
CompletableFuture<SecondValue> f2 = CompletableFuture.supplyAsync(() -> service.getSecondValue());
CompletableFuture<ObjectToInstantiate> combineFuture = f1.thenCombine(f2, (firstValue, secondValue) -> new ObjectToInstantiate (firstValue, secondValue));
ObjectToInstantiate myObject = combineFuture .join();
What this is doing is creating 2 async threads that return values. f1.thenCombine takes the values of both when they are completed successfully and combines the values from both to create your new object.
You are now not using the side affects of methods, but actually returning and moving around values to create your new object.
Also depending on how you have your constructors on your object you might be able to do
f1.thenCombine(f2, ObjectToInstantiate::new);
you can also do this for the async methods too
CompletableFuture.supplyAsync(service::getFirstValue)
Also if you have an executor service already you can change
CompletableFuture.supplyAsync(() -> service.getFirstValue);
to
CompletableFuture.supplyAsync(() -> service.getFirstValue, myExecutorService);
ExecutorService es = Executors.newFixedThreadPool(1);
List<Callable<Void>> tasks = Arrays.asList(task1, task2);
es.invokeAll(task); // Run them all
Regarding "threading":
You turn to an ExecutorService, but then you can't use Threads:
Thread getFirstValueThread = new Thread(() -> instance.setFirstValue(service.getFirstValue));
Could become:
Runnable r1 = instance::setFirstValue(service.getFirstValue);
( you use a method reference here; instead of a lambda )
and then
ExecutorService es = Executors.newFixedThreadPool(whatever);
es.submit(r1);
...
es.shutdown();
Where: you make the choice which kind of service you actually want to create. Could be a threadpool, or something else.
But beyond that; your code looks strange. Why would you want to set fields in an object (with values that are fetched immediately using threads)?! I would rather step back here; and not try to translate your code into "newer" concepts; but understand why it is doing such strange things; and get sorted out.
In other words: the real problem of that code is not how it is doing things; but why it is doing it!

Categories

Resources