I have method that is checking the CompletableFuture execution time. If such CompletableFuture is executing for more than 2 seconds i want to kill this task. But how can I doit if i don't have control overy thread where CompletableFuture methods are executed ?
final CompletableFuture<List<List<Student>>> responseFuture = new CompletableFuture<>();
responseFuture.supplyAsync(this::createAllRandomGroups)
.thenAccept(this::printGroups)
.exceptionally(throwable -> {
throwable.printStackTrace();
return null;
});
createAllRandomGroups()
private List<List<Student>> createAllRandomGroups() {
System.out.println("XD");
List<Student> allStudents = ClassGroupUtils.getActiveUsers();
Controller controller = Controller.getInstance();
List<List<Student>> groups = new ArrayList<>();
int groupSize = Integer.valueOf(controller.getGroupSizeComboBox().getSelectionModel().getSelectedItem());
int numberOfGroupsToGenerate = allStudents.size() / groupSize;
int studentWithoutGroup = allStudents.size() % groupSize;
if (studentWithoutGroup != 0) groups.add(this.getListOfStudentsWithoutGroup(allStudents, groupSize));
for(int i = 0; i < numberOfGroupsToGenerate; i++) {
boolean isGroupCreated = false;
while (!isGroupCreated){
Collections.shuffle(allStudents);
List<Student> newGroup = this.createNewRandomGroupOfStudents(allStudents, groupSize);
groups.add(newGroup);
if (!DataManager.isNewGroupDuplicated(newGroup.toString())) {
isGroupCreated = true;
allStudents.removeAll(newGroup);
}
}
}
DataManager.saveGroupsToCache(groups);
return groups;
}
printGroups()
private void printGroups(List<List<Student>> lists) {
System.out.println(lists);
}
This statement responseFuture.cancel(true); does not kill thread where responseFuture is doing the methods. So what is the most elegant way to terminate CompletableFuture thread ?
When you create a chain of CompletableFuture stages like b = a.thenApply(function), this handy method creates a setup of different components. Basically, these components refer to each other as a → function → b, so the completion of a will trigger the evaluation of function which will first pre-check whether b still is not completed, then evaluate your function and attempt to complete b with the result.
But b itself has no knowledge of function or the thread that will evaluate it. In fact, function is not special to b, anyone could call complete, completeExceptionally or cancel on it from any thread, the first one winning. Hence, the completable in the class name.
The only way to get hands on the threads evaluating the functions, is to be in control of them right from the start, e.g.
ExecutorService myWorkers = Executors.newFixedThreadPool(2);
CompletableFuture<FinalResultType> future
= CompletableFuture.supplyAsync(() -> generateInitialValue(), myWorkers)
.thenApplyAsync(v -> nextCalculation(v), myWorkers)
.thenApplyAsync(v -> lastCalculation(v), myWorkers);
future.whenComplete((x,y) -> myWorkers.shutdownNow());
Now, the completion of future, e.g. via cancellation, will ensure that no new evaluation will be triggered by this chain and further makes an attempt to interrupt ongoing evaluations, if any.
So you can implement a timeout, e.g.
try {
try {
FinalResultType result = future.get(2, TimeUnit.SECONDS);
System.out.println("got "+result);
}
catch(TimeoutException ex) {
if(future.cancel(true)) System.out.println("cancelled");
else System.out.println("got "+future.get());
}
}
catch(ExecutionException|InterruptedException ex) {
ex.printStackTrace();
}
Not that the rejection of tasks due to the shutdown of the thread pool may cause some of the intermediate future to never complete, but for this chain of stages, this is irrelevant. All that matters, is, that the final stage future is completed, which is guaranteed, as it is its completion which triggers the shutdown.
The only way to terminate a thread is via interruption, which is a cooperative mechanism. This means the the thread must implement interruption logic, by handling the InterruptedException.
But it is a really bad practice to interrupt threads that you don't own, which I think is your case.
Related
I have N tasks to execute, and the number of tasks is not fixed. The next task can only be executed after the previous task is completed. How can the entire task chain be executed asynchronously?
If the number of tasks is fixed, such as N=2, I can use the following code. How to do it if N is not fixed
public void futureTest() throws InterruptedException {
CompletableFuture<Integer> finalFuture = new CompletableFuture<>();
CompletableFuture<Integer> cf1 = doTask(1);
AtomicReference<CompletableFuture<Integer>> cf2 = new AtomicReference<>(new CompletableFuture<>());
cf1.whenComplete(((integer1, throwable1) -> {
if (throwable1 != null) {
finalFuture.completeExceptionally(throwable1);
return;
}
// when task1 complete then submit task2
cf2.set(doTask(2));
cf2.get().whenComplete(((integer2, throwable2) -> {
if (throwable2 != null) {
finalFuture.completeExceptionally(throwable2);
return;
}
finalFuture.complete(integer2);
}));
}));
finalFuture.whenComplete(((integer, throwable) -> {
System.out.println("all task is done");
}));
Thread.sleep(1000000);
}
private CompletableFuture<Integer> doTask(int index) {
CompletableFuture<Integer> cf = new CompletableFuture<>();
// Simulate task execution
THREAD_POOL.execute(() -> {
Thread.sleep(3_000);
cf.complete(index);
});
return cf;
}
I looked at Compeltable's API docs and none of them seem to solve my problem. I tried to use a loop to control the task submission, but all failed, unable to submit the next task after the previous task is completed
Refer to this answer on this thread Click here. Seems a duplicate of this question.
thenRun method is used to run the task after the previous future is completed successfully. This method will be skipped in case of any failures in previous stages.
whenComplete method is used as the final stage of execution chain. Here you will receive the composed result of all the other functions in the supply chain and you can choose to fail your future or handle exceptions accordingly inside this.
You can compose the futures for the individual tasks via CompletableFuture#thenCompose in a loop:
CompletableFuture<?> future = createFirstTask();
while (hasMoreTasks()) {
future = future.thenCompose(this::createNextTask);
}
Here every next tasks depends on the result of the previous one until no more task is left.
Conceptionally this is a fold operation, which unfortunately is not part of the API of CompletableFuture. But if you don't mind using my better future library (which is just a thin wrapper around CompleteableFuture), I just recently added support for folding streams of futures there.
// assume: serviceCall1 throws an exception after 1s, servserviceCall2 runs 10s without exception
CompletableFuture<String> serviceCall1Future = serviceCall1.execute();
CompletableFuture<String> serviceCall2Future = serviceCall2.execute();
CompletableFuture<Void> allOffFuture = CompletableFuture.allOf(serviceCall1Future, serviceCall2Future);
// does not work, will be called after thread 2 has finished
allOffFuture.exceptionally( ex -> { allOffFuture.cancel(true); return null; } );
try {
// waiting for threads to finish
allOffFuture.join();
} catch (CompletionException e) {
// does not work, here we come after thread 2 has finished
allOffFuture.cancel(true);
}
If one thread throws an exception, in my case it doesnt make any sense for the other thread(s) to keep on running, so I want them both (all in case of more than 2 threads) to stop . How can I achieve that ?
I guess something like this should work:
CompletableFuture<String> serviceCall1Future = serviceCall1.execute();
CompletableFuture<String> serviceCall2Future = serviceCall2.execute();
CompletableFuture<String> foo1 = serviceCall1Future.whenComplete((result,exception) -> {if(exception != null) serviceCall2Future.cancel(true);});
CompletableFuture<String> foo2 = serviceCall2Future.whenComplete((result,exception) -> {if(exception != null) serviceCall1Future.cancel(true);});
CompletableFuture<Void> allOffFuture = CompletableFuture.allOf(foo1, foo2);
// ... rest of your code
This cancels the other future when the one completes with an exception.
If you are using an ExecutorService with CompletableFuture, you can use Shutdowns methods like shutdown() or shutdownNow().
If you want to shut down the ExecutorService immediately, you can call the shutdownNow() method. This will attempt to stop all executing tasks right away, and skips all submitted but non-processed tasks. There are no guarantees given about the executing tasks. Perhaps they stop, perhaps the execute until the end. It is a best effort attempt. Here is an example of calling ExecutorService shutdownNow()
See -> https://jenkov.com/tutorials/java-util-concurrent/executorservice.html#executorservice-shutdown
I have method that is checking the CompletableFuture execution time. If such CompletableFuture is executing for more than 2 seconds i want to kill this task. But how can I doit if i don't have control overy thread where CompletableFuture methods are executed ?
final CompletableFuture<List<List<Student>>> responseFuture = new CompletableFuture<>();
responseFuture.supplyAsync(this::createAllRandomGroups)
.thenAccept(this::printGroups)
.exceptionally(throwable -> {
throwable.printStackTrace();
return null;
});
createAllRandomGroups()
private List<List<Student>> createAllRandomGroups() {
System.out.println("XD");
List<Student> allStudents = ClassGroupUtils.getActiveUsers();
Controller controller = Controller.getInstance();
List<List<Student>> groups = new ArrayList<>();
int groupSize = Integer.valueOf(controller.getGroupSizeComboBox().getSelectionModel().getSelectedItem());
int numberOfGroupsToGenerate = allStudents.size() / groupSize;
int studentWithoutGroup = allStudents.size() % groupSize;
if (studentWithoutGroup != 0) groups.add(this.getListOfStudentsWithoutGroup(allStudents, groupSize));
for(int i = 0; i < numberOfGroupsToGenerate; i++) {
boolean isGroupCreated = false;
while (!isGroupCreated){
Collections.shuffle(allStudents);
List<Student> newGroup = this.createNewRandomGroupOfStudents(allStudents, groupSize);
groups.add(newGroup);
if (!DataManager.isNewGroupDuplicated(newGroup.toString())) {
isGroupCreated = true;
allStudents.removeAll(newGroup);
}
}
}
DataManager.saveGroupsToCache(groups);
return groups;
}
printGroups()
private void printGroups(List<List<Student>> lists) {
System.out.println(lists);
}
This statement responseFuture.cancel(true); does not kill thread where responseFuture is doing the methods. So what is the most elegant way to terminate CompletableFuture thread ?
When you create a chain of CompletableFuture stages like b = a.thenApply(function), this handy method creates a setup of different components. Basically, these components refer to each other as a → function → b, so the completion of a will trigger the evaluation of function which will first pre-check whether b still is not completed, then evaluate your function and attempt to complete b with the result.
But b itself has no knowledge of function or the thread that will evaluate it. In fact, function is not special to b, anyone could call complete, completeExceptionally or cancel on it from any thread, the first one winning. Hence, the completable in the class name.
The only way to get hands on the threads evaluating the functions, is to be in control of them right from the start, e.g.
ExecutorService myWorkers = Executors.newFixedThreadPool(2);
CompletableFuture<FinalResultType> future
= CompletableFuture.supplyAsync(() -> generateInitialValue(), myWorkers)
.thenApplyAsync(v -> nextCalculation(v), myWorkers)
.thenApplyAsync(v -> lastCalculation(v), myWorkers);
future.whenComplete((x,y) -> myWorkers.shutdownNow());
Now, the completion of future, e.g. via cancellation, will ensure that no new evaluation will be triggered by this chain and further makes an attempt to interrupt ongoing evaluations, if any.
So you can implement a timeout, e.g.
try {
try {
FinalResultType result = future.get(2, TimeUnit.SECONDS);
System.out.println("got "+result);
}
catch(TimeoutException ex) {
if(future.cancel(true)) System.out.println("cancelled");
else System.out.println("got "+future.get());
}
}
catch(ExecutionException|InterruptedException ex) {
ex.printStackTrace();
}
Not that the rejection of tasks due to the shutdown of the thread pool may cause some of the intermediate future to never complete, but for this chain of stages, this is irrelevant. All that matters, is, that the final stage future is completed, which is guaranteed, as it is its completion which triggers the shutdown.
The only way to terminate a thread is via interruption, which is a cooperative mechanism. This means the the thread must implement interruption logic, by handling the InterruptedException.
But it is a really bad practice to interrupt threads that you don't own, which I think is your case.
I've been experimenting with different ways to handle blocking methods with disconnected results while maintaining state which might have been interrupted. I've found it to be frustrating having to deal with disparate classes and methods where sending and receiving are difficult to align.
In the following example, SomeBlockingMethod() normally returns void as a message is sent to some other process. But instead I've made it synchronized with a listener which receives the result. By spinning it off to a thread, I can wait() for the result with a timeout or indefinitely.
This is nice because once the result is returned, I can continue working with a particular state which I had to pause while waiting for the result of the threaded task.
This there anything wrong with my approach?
Although this question may seem generic, I am specifically looking for advice on threading in Java.
Example pseudocode:
public class SomeClass implements Command {
#Override
public void onCommand() {
Object stateObject = new SomeObjectWithState();
// Do things with stateObject
Runnable rasync = () -> {
Object r = SomeBlockingMethod();
// Blocking method timed out
if (r == null)
return;
Runnable rsync = () -> {
// Continue operation on r which must be done synchronously
// Also do things with stateObject
};
Scheduler().run(rsync);
};
Scheduler().run(rasync);
}
Update with CompletableFuture:
CompletableFuture<Object> f = CompletableFuture.supplyAsync(() -> {
return SomeBlockingMethod();
});
f.thenRun(() -> { () -> {
String r = null;
try {
r = f.get();
}
catch (Exception e) {
e.printStackTrace();
}
// Continue but done asynchronously
});
or better yet:
CompletableFuture.supplyAsync(() -> {
return SomeBlockingMethod();
}).thenAccept((
Object r) -> {
// Continue but done asynchronously
});
The problem with using strictly CompletableFuture is that CompletableFuture.thenAccept is run from the global thread pool and is not guaranteed to be synchronous with the calling thread.
Adding the scheduler back for the synchronous task fixes this:
CompletableFuture.supplyAsync(() -> {
return SomeBlockingMethod();
}).thenAccept((
Object r) -> {
Runnable rsync = () -> {
// Continue operation on r which must be done synchronously
};
Scheduler().run(rsync);
});
A caveat of using CompletableFuture compared to the complete scheduler method is that any previous state which exists outside must be final or effectively final.
You should check out RxJava, it uses stream manipulation and has threading support.
api.getPeople()
.observeOn(Schedulers.computation())
.filter(p -> return p.isEmployee();)
.map(p -> return String.format("%s %s - %s", p.firstName(), p.lastName(), p.payrollNumber());)
.toList()
.observerOn(<ui scheudler>)
.subscirbe(p -> screen.setEmployees(p);)
I'v got ConcurrentLinkedDeque which I'm using for synchronic push/pop elements,
and I'v got some async tasks which are taking one element from stack and if this element has neighbors It's pushing it to stack.
Example code:
private ConcurrentLinkedDeque<Item> stack = new ConcurrentLinkedDeque<>();
private ExecutorService exec = Executors.newFixedThreadPool(5);
while ((item = stack.pollFirst()) != null) {
if (item == null) {
} else {
Runnable worker = new Solider(this, item);
exec.execute(worker);
}
}
class Solider{
public void run(){
if(item.hasNeighbors){
for(Item item:item.neighbors){
stack.push(item)
}
}
}
}
I would like to have additional statement in while loop which answers the question - "any task in Executor is working?"
There isn't a clean way to check if all Runnables are done if you use ExecutorService.execute(Runnable). Unless you build a mechanism to do so in the Runnable itself (which is sloppy in my opinion).
Instead:
Use ExecutorService.submit(Runnable). This method will return a Future<?> which is a handle to the result of a Runnable. Using Futures provides a clean way to check results.
All you have to do is maintain a list of Futures that you submit, and then you can iterate over the whole list of Futures and either:
A) wait for all the futures to be done in a blocking way or
B) check if all the futures are done in a non-blocking way.
Here is a code example:
List<Future<?>> futures = new ArrayList<Future<?>>();
ExecutorService exec = Executors.newFixedThreadPool(5);
// Instead of using exec.execute() use exec.submit()
// because it returns a monitorable future
while((item = stack.pollFirst()) != null){
Runnable worker = new Solider(this, item);
Future<?> f = exec.submit(worker);
futures.add(f);
}
// A) Await all runnables to be done (blocking)
for(Future<?> future : futures)
future.get(); // get will block until the future is done
// B) Check if all runnables are done (non-blocking)
boolean allDone = true;
for(Future<?> future : futures){
allDone &= future.isDone(); // check if future is done
}
Update: with Java 8+ CompletableFutures you can manage this with its new callback functions. First you will need to create all of the CompletableFutures you need which will also start running, eg:
We need to accumulate all the futures generated in an Array in order to pass them later to CompletableFuture.allOf(CompletableFutures...)
So let's say you have a list of people you want to calculate its days until birthday asynchronously:
First we create all those needed futures and collect them together in an array:
CompletableFuture<?>[] completables = people.stream()
.map(p -> createCompletableFuture(p))
.toArray(CompletableFuture<?>[]::new);
private CompletableFuture createCompletableFuture(Person p) {
return CompletableFuture.runAsync(daysUntillBirthday(p));
}
Then you pass those completables to a new CompletableFuture:
CompletableFuture c = CompletableFuture.allOf(completables)
And you can now check if there are still futures running with:
c.isDone()
This may not be the cleanest solution, but you can use ThreadPoolExecutor.getActiveCount() to check how many threads are actively executing tasks.
Implementing this within a while loop with a simple condition to check if the active thread count is zero is a palatable solution.
Here is a code example:
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(5);
for (int x = 0; x < 4; x++) {
Runnable worker = new Solider(this,item);
executor.execute(worker);
}
// Now check for active threads.
while(executor.getActiveCount()!=0)
{
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
executor.shutdown();
The while block directly answers your question.
IE - If the while block is active, tasks are being executed.