Callable sequential execution - java

I know Callable allows to return a value or checked exception whereas Runnable doesn't. This question is not about the difference between the two interfaces but about the sequential returns of the values in following code.
Please have a look at the following code segment.
ExecutorService executorService = Executors.newCachedThreadPool();
List<Future<String>> futureList = new ArrayList<Future<String>>();
for (int i=0;i<10;i++) {
Runner runner = new Runner(i);
Future<String> future = executorService.submit(runner);
futureList.add(future);
}
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.DAYS);
for (Future<String> integerFuture : futureList) {
System.out.println("Returned value is : " + integerFuture.get());
}
The Runner class for this code is provided below.
public class Runner implements Callable<String> {
private int id;
public Runner(Integer id) {
this.id = id;
}
#Override
public String call() throws Exception {
Random randomWait = new Random();
Thread.sleep(randomWait.nextInt(5)*1000);
Random random = new Random();
int randomInt = random.nextInt(100);
return id + " - " + randomInt;
}
}
The above code always provides a sequential response despite the fact that the threads executing them may sleep different seconds.
Returned value is : 0 - 19
Returned value is : 1 - 88
Returned value is : 2 - 99
........
Returned value is : 9 - 42
But by comparison the following code segment provides more meaningful response, as the threads sleeps different time periods.
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i=0;i<10;i++) {
Runner runner = new Runner(i);
executorService.submit(runner);
}
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.DAYS);
The runner class for about segment is given below.
public class Runner implements Runnable {
private int id;
public Runner(Integer id) {
this.id = id;
}
#Override
public void run() {
Random randomWait = new Random();
try {
Thread.sleep(randomWait.nextInt(5)*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Runner : " + id + " Finished.");
}
}
As expected the response of this thread was non sequential.
Runner : 5 Finished.
Runner : 9 Finished.
Runner : 1 Finished.
Runner : 3 Finished.
........
So my question is why does the fist code segment with futures and callable response is always sequential ? It seems to me that the main thread waits till end end of executing all the threads and provides a sequential output. But there is nothing about it is mentioned in the javadoc. If the response was something like second one I could have understood it.

First you explicitly create the list of futures with ordered IDs, then you iterate over it in order:
for (Future<String> integerFuture : futureList) {
System.out.println("Returned value is : " + integerFuture.get());
There is no other possible result but sequential IDs. Each time you call integerFuture.get(), the call will block as long as needed for the future to provide the result.
In the second example you output to the console from within the Callable, thus you get output in the order of completion.

So my question is why does the fist code segment with futures and callable response is always sequential?
Because you're specifically asking for the result of the Futures in the order in which they were submitted:
for (Future<String> integerFuture : futureList) {
System.out.println("Returned value is : " + integerFuture.get());
Here, Future.get() will block until the call has completed - and your list is constructed by submitting callables; futureList.get(0) is always going to be the future related to the first callable submitted, regardless of whether it's the first one to complete.

Related

Terminate other Future tasks running in when condition is met in one for the Future Task

Using java 8
I'm trying to write a prog to download log files from diff servers and search a given text in these log files. I'm doing is synchronously right now. I want to do it in parallel and found out that it can be done using Future in java. I'm using apache.commons.io for downloading file from URL.
Here is code snippet:
ExecutorService executorService = Executors.newCachedThreadPool();
List<Future<XCluster>> clusterFutures = new ArrayList<>();
for(XCluster cluster: clusters) {
clusterFutures.add(executorService.submit(() -> {
return downloadAndSearch(textToSearch, cluster);
}));
}
//For now I'm not doing anything with returned value from Future
But now I want to terminate other download-search operation started under Future as given search is expected to be found in only one of the servers. So there is no need to continue on other Future tasks which I started. can any one suggest a way to do this? I'm using java 8, other options are also welcome. Thanks In Advance!
The ExecutorService has a shutdownNow method which will stop all threads and shut down the service.
Edit:
I made some experiments with shutDownNow and as I see it can't stop the threads as I thought. AFAIK It uses interrupts() but not all thread react to interrupt.
So the best alternative I can come up with:
First, create an Indicator class:
public static class Indicator{
private boolean isReady = false;
public void ready(){
isReady = true;
}
public boolean isReady(){
return isReady;
}
}
The threads you start should share one Indicator instance to communicate.
So you can create a Callable like this:
public static class Processor implements Callable<Integer> {
private volatile Indicator indicator;
private Integer number;
public Processor(Integer integer, Indicator isReady){
this.number = integer;
this.indicator = isReady;
}
#Override
public Integer call() throws Exception {
System.out.println("Thread started:" + Thread.currentThread().getId());
int counter = 0;
while (!indicator.isReady &&counter < number) {
// Make complicated things
Math.sin(counter);
counter++;
}
if(indicator.isReady){
//another thread finished
//delete resources
System.out.println("Thread interrupted: " + Thread.currentThread().getId() + " " + counter);
return -1;
} else {
System.out.println("Thread finished: " + Thread.currentThread().getId() + " " + counter);
indicator.ready();
return counter;
}
}
}
This way when the first thread is ready it can stop the others and they clean up after himselves.
I tried this as follows:
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
List<Future<Integer>> clusterFutures = new ArrayList<>();
Indicator indicator = new Indicator();
clusterFutures.add(executorService.submit(new Processor(100, indicator)));
clusterFutures.add(executorService.submit(new Processor(10000, indicator)));
clusterFutures.add(executorService.submit(new Processor(10000000,indicator)));
}
A sample output:
Thread started:11
Thread started:12
Thread finished: 11 100
Thread interrupted: 12 1001
Thread started:13
Thread interrupted: 13 0
Sidenote: the referenced classes don't have to be static inner classes just it was easier to make experiments in one file.
In terms of code, the simplest solution is to have a shutdown thread that cancels all the futures:
final ExecutorService executorService = Executors.newCachedThreadPool();
final ExecutorService shutdownService = Executors.newSingleThreadExecutor();
List<Future<XCluster>> clusterFutures = new ArrayList<>();
for(XCluster cluster: clusters) {
clusterFutures.add(executorService.submit(() -> {
boolean cancelOthers = false;
try {
XCluster result = downloadAndSearch(textToSearch, cluster);
cancelOthers = yourPredicateOfSuccess();
return result;
} finally {
if (cancelOthers) {
shutdownService.execute(() -> {
executorService.shutdownNow();
});
}
}
}));
}
The other thread and the try-finally is important because this makes sure that you won't cancel the almost-successful method run.

Learning about Threads

I have written a simple program, that is intended to start a few threads. The threads should then pick a integer n from an integer array, use it to wait n and return the time t the thread waited back into an array for the results.
If one thread finishes it's task, it should pick the next one, that has not yet being assigned to another thread.
Of course: The order in the arrays has to be maintained, so that integers and results match.
My code runs smoothly as far I see.
However I use one line of code block I find in particular unsatisfying and hope there is a good way to fix this without changing too much:
while(Thread.activeCount() != 1); // first evil line
I kinda abuse this line to make sure all my threads finish getting all the tasks done, before I access my array with the results. I want to do that to prevent ill values, like 0.0, Null Pointer Exception... etc. (in short anything that would make an application with an actual use crash)
Any sort of constructive help is appreciated. I am also not sure, if my code still runs smoothly for very very long arrays of tasks for the threads, for example the results no longer match the order of the integer.
Any constructive help is appreciated.
First class:
public class ThreadArrayWriterTest {
int[] repitions;
int len = 0;
double[] timeConsumed;
public boolean finished() {
synchronized (repitions) {
return len <= 0;
}
}
public ThreadArrayWriterTest(int[] repitions) {
this.repitions = repitions;
this.len = repitions.length;
timeConsumed = new double[this.len];
}
public double[] returnTimes(int[] repititions, int numOfThreads, TimeConsumer timeConsumer) {
for (int i = 0; i < numOfThreads; i++) {
new Thread() {
public void run() {
while (!finished()) {
len--;
timeConsumed[len] = timeConsumer.returnTimeConsumed(repititions[len]);
}
}
}.start();
}
while (Thread.activeCount() != 1) // first evil line
;
return timeConsumed;
}
public static void main(String[] args) {
long begin = System.currentTimeMillis();
int[] repitions = { 3, 1, 3, 1, 2, 1, 3, 3, 3 };
int numberOfThreads = 10;
ThreadArrayWriterTest t = new ThreadArrayWriterTest(repitions);
double[] times = t.returnTimes(repitions, numberOfThreads, new TimeConsumer());
for (double d : times) {
System.out.println(d);
}
long end = System.currentTimeMillis();
System.out.println("Total time of execution: " + (end - begin));
}
}
Second class:
public class TimeConsumer {
double returnTimeConsumed(int repitions) {
long before = System.currentTimeMillis();
for (int i = 0; i < repitions; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
long after = System.currentTimeMillis();
double ret = after - before;
System.out.println("It takes: " + ret + "ms" + " for " + repitions + " runs through the for-loop");
return ret;
}
}
The easiest way to wait for all threads to complete is to keep a Collection of them and then call Thread.join() on each one in turn.
In addition to .join() you can use ExecutorService to manage pools of threads,
An Executor that provides methods to manage termination and methods
that can produce a Future for tracking progress of one or more
asynchronous tasks.
An ExecutorService can be shut down, which will cause it to reject new
tasks. Two different methods are provided for shutting down an
ExecutorService. The shutdown() method will allow previously submitted
tasks to execute before terminating, while the shutdownNow() method
prevents waiting tasks from starting and attempts to stop currently
executing tasks. Upon termination, an executor has no tasks actively
executing, no tasks awaiting execution, and no new tasks can be
submitted. An unused ExecutorService should be shut down to allow
reclamation of its resources.
Method submit extends base method Executor.execute(Runnable) by
creating and returning a Future that can be used to cancel execution
and/or wait for completion. Methods invokeAny and invokeAll perform
the most commonly useful forms of bulk execution, executing a
collection of tasks and then waiting for at least one, or all, to
complete.
ExecutorService executorService = Executors.newFixedThreadPool(maximumNumberOfThreads);
CompletionService completionService = new ExecutorCompletionService(executorService);
for (int i = 0; i < numberOfTasks; ++i) {
completionService.take();
}
executorService.shutdown();
Plus take a look at ThreadPoolExecutor
Since java provides more advanced threading API with concurrent package, You should have look into ExecutorService, which simplifies thread management mechanism.
Simple to solution to your problem.
Use Executors API to create thread pool
static ExecutorService newFixedThreadPool(int nThreads)
Creates a thread pool that reuses a fixed number of threads operating off a shared unbounded queue.
Use invokeAll to wait for all tasks to complete.
Sample code:
ExecutorService service = Executors.newFixedThreadPool(10);
List<MyCallable> futureList = new ArrayList<MyCallable>();
for ( int i=0; i<12; i++){
MyCallable myCallable = new MyCallable((long)i);
futureList.add(myCallable);
}
System.out.println("Start");
try{
List<Future<Long>> futures = service.invokeAll(futureList);
for(Future<Long> future : futures){
try{
System.out.println("future.isDone = " + future.isDone());
System.out.println("future: call ="+future.get());
}
catch(Exception err1){
err1.printStackTrace();
}
}
}catch(Exception err){
err.printStackTrace();
}
service.shutdown();
Refer to this related SE question for more details on achieving the same:
wait until all threads finish their work in java

Multithreaded approach using java Executor interface

I am trying to implement the multithreaded approach using executor interface where i have produced multiple threads in main class
class Main
{
private static final int NTHREADS = 10;
public static void main(String[] args)
{
.........
String str = createThreads(document);
.............
}
public String createThreads(String docString)
{
........
.......
Map<String,String> iTextRecords = new LinkedHashMap<String, String>();
if(!iText.matches(""))
{
String[] tokenizedItext = iText.split("\\^");
ExecutorService executor = Executors.newFixedThreadPool(NTHREADS);
for(int index = 0 ;index < tokenizedItext.length;index++)
{
Callable<Map<String,String>> worker = null;
Future<Map<String,String>> map = null;
if(tokenizedItext[index].matches("^[0-9.<>+-= ]+$") || tokenizedItext[index].matches("^\\s+$"))
{
iTextRecords.put(tokenizedItext[index],tokenizedItext[index]);
}
else
{
worker = new MultipleDatabaseCallable(tokenizedItext[index],language);
map = executor.submit(worker);
try
{
iTextRecords.putAll(map.get());
}
catch(InterruptedException ex)
{
ex.printStackTrace(System.out);
}
catch(ExecutionException ex)
{
ex.printStackTrace(System.out);
}
}
}
executor.shutdown();
// Wait until all threads are finish
while (!executor.isTerminated())
{
}
}
}
The Callable class is as
class MultipleDatabaseCallable implements Callable<Map<String,String>>
{
#Override
public Map<String, String> call() throws Exception {
System.out.println("Entering: "+Thread.currentThread().getName());
Map<String,String> map = new HashMap<String,String>();
for(int i =0;i<50000;i++)
{
for(int i1 = 0 ;i1<5000;i1++)
{
for(int i2 =0;i2 <500;i2++)
{
}
}
}
System.out.println("Exiting: "+Thread.currentThread().getName());
return map;
}
}
output I am getting is
Entering: pool-1-thread-1
Exiting: pool-1-thread-1
Entering: pool-1-thread-2
Exiting: pool-1-thread-2
Entering: pool-1-thread-3
Exiting: pool-1-thread-3
Entering: pool-1-thread-4
Exiting: pool-1-thread-4
Entering: pool-1-thread-5
Exiting: pool-1-thread-5
Entering: pool-1-thread-6
Exiting: pool-1-thread-6
While looking at the output it seems like only one thread is entering at a time in the call method and other thread enters only when previous one exist. However it is expected that the multiple threads should enter and execute call() method. Also when I am executing the same program by making NTHREADS = 1. it is taking same time as it is taking with NTHREADS =10
so it seems like the application is running as good as a single threaded application.please suggest whats wrong i am doing in implementation.
Thanks
When you call
map = executor.submit(worker);
the value returned map in this case is a Future. Meaning that it does not have a value, until the callable has returned one. Now when you call
iTextRecords.putAll(map.get());
What happens is that the current thread blocks (inside the map.get()) waiting for the callable to return (in the other thread).
Since you always wait for a callable to be finished (per map.get()) before submitting a new one (per executor.submit()) you enforce the sequential execution you observe.
In order to execute the tasks in parallel, you have to start them all before calling get for the first time. You could for instance create an ArrayList<Future<Map<String,String>>> futures = ... and then
do
futures.add(executor.submit(worker));
to submit the tasks (no need for the map variable) and create a second loop (after the for(int i ...) loop):
for(Future<Map<String,String>> f: futures) {
iTextRecords.putAll(f.get);
}
You must collect your futures while you submit the callables. Call get() on your futures only after you finish submitting.

How to Synchronize Threads

In this multithreading program, when I run it, I always get the output in some random order. But I was wondering if there is any way I can make this program to work in synchronized mode. Like when I runt it then for the first thread it should print out everything, then for second thread it should print out something, then for third thread it should print out everything etc etc. So sample output should be like this for each thread-
Task 1 Started
original: Hello World
Difference:- 0
Task 1 Ended
Task 2 Started
original: Hello World
Difference:- 0
Task 2 Ended
............
............
Task 15 Started
original: Hello World
Difference:- 0
Task 15 Ended
This is my below program. Any suggestions will be appreciated.
class ThreadTask implements Runnable {
private int id;
public ThreadTask(int id) {
this.id = id;
}
public synchronized void run() {
System.out.println("Task " + id + " Started ");
String originalString = "Hello World";
System.out.println("original: " + originalString);
System.out.println("Task " + id + " Ended ");
}
}
public class TestPool {
public static void main(String[] args) throws InterruptedException {
int size = 5; //Integer.parseInt(args[0]);
// create thread pool with given size
ExecutorService service = Executors.newFixedThreadPool(size);
// queue some tasks
for(int i = 1; i <= 3 * size; i++) {
service.submit(new ThreadTask(i));
}
// wait for termination
service.shutdown();
service.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
}
}
You commented on Jakub's answer as follows:
Can you give me example basis on my code as I just started learning about threading. It will be of great help to me.
What Jakub is saying is that forcing threads to run in a fixed sequence defeats the purpose of using threads in the first place. Think about this.
If you really do want / need your example to run the tasks in order, you may as well do this:
for (int i = 1; i <= 3 * size; i++) {
new ThreadTask(i).run();
}
i.e. just run the runnables in the current thread.
Or you could set the maximum pool size to 1, which forces the service to run the tasks in order. (Of course, this defeats the point of using threads. You won't get any parallelism this way.)
A more sensible approach would be to have each thread return its results in a Future, and then have the main thread fetch the value from each future (in the required order) and print it. Basically, you want to allow the threads to run in any order (and in parallel, if you have multiple cores), but then impose the ordering when you access the results.
The essence of thread is that they can run simultaneously, if you want them to run in order, simply do not use Thread.
There's another kind of requirement, that maybe you want several jobs to work together (simultaneously), but in a given order. In this case, I highly suggest you to implement a queuing system. That is, build a queue like
Queue <C> q
And a thread
class T implements Runnable {
public void run() {
while (!q.empty()) {
// Do something
}
}
}
You can use Runnable through ExecutorService, like the code that you've used.
You can also add some elements into the queue in "Do something" section of previous code, then you can control the order of jobs by yourself.
You can save the the reference to the previous thread and hook up the next thread to the previous one using join(). That will ensure the threads will be run in a series (next one not starting unless the previous one finished). But the point of doing that is eluding me.
public class TestPool
{
static class ThreadTask extends Thread
{
private int id;
private Thread previous;
public ThreadTask(int id, Thread previous){
this.id = id;
this.previous = previous;
}
public void run(){
if(previous != null){
try{
previous.join();
}
catch(InterruptedException e){
e.printStackTrace();
}
}
System.out.println("Task " + id + " Started ");
String originalString = "Hello World";
System.out.println("original: " + originalString);
System.out.println("Task " + id + " Ended ");
}
}
public static void main(String[] args) throws InterruptedException{
int size = 5; // Integer.parseInt(args[0]);
// create thread pool with given size
ExecutorService service = Executors.newFixedThreadPool(size);
Thread previous = null;
// queue some tasks
for(int i = 1; i <= 3 * size; i++){
Thread thread = new ThreadTask(i, previous);
previous = thread;
thread.start();
//service.submit(thread);
}
// wait for termination
//service.shutdown();
//service.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
}
}
Not tested, sry. I don't also know what the ExecutorService is doing, it might break this. Note that I need to be a Thread, being Runnable is not enough. Also, run() needs not be synchronised, as it will be called only once per execution. And you should not start the threads with run(), but with start().
EDIT: I just tried to run it, and the ExecutorService is fu**ing things up. If you just start the thread (like the my code does), then it's working.

When should I use a CompletionService over an ExecutorService?

I just found CompletionService in this blog post. However, this does't really showcases the advantages of CompletionService over a standard ExecutorService. The same code can be written with either. So, when is a CompletionService useful?
Can you give a short code sample to make it crystal clear? For example, this code sample just shows where a CompletionService is not needed (=equivalent to ExecutorService)
ExecutorService taskExecutor = Executors.newCachedThreadPool();
// CompletionService<Long> taskCompletionService =
// new ExecutorCompletionService<Long>(taskExecutor);
Callable<Long> callable = new Callable<Long>() {
#Override
public Long call() throws Exception {
return 1L;
}
};
Future<Long> future = // taskCompletionService.submit(callable);
taskExecutor.submit(callable);
while (!future.isDone()) {
// Do some work...
System.out.println("Working on something...");
}
try {
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
Omitting many details:
ExecutorService = incoming queue + worker threads
CompletionService = incoming queue + worker threads + output queue
With ExecutorService, once you have submitted the tasks to run, you need to manually code for efficiently getting the results of the tasks completed.
With CompletionService, this is pretty much automated. The difference is not very evident in the code you have presented because you are submitting just one task. However, imagine you have a list of tasks to be submitted. In the example below, multiple tasks are submitted to the CompletionService. Then, instead of trying to find out which task has completed (to get the results), it just asks the CompletionService instance to return the results as they become available.
public class CompletionServiceTest {
class CalcResult {
long result ;
CalcResult(long l) {
result = l;
}
}
class CallableTask implements Callable<CalcResult> {
String taskName ;
long input1 ;
int input2 ;
CallableTask(String name , long v1 , int v2 ) {
taskName = name;
input1 = v1;
input2 = v2 ;
}
public CalcResult call() throws Exception {
System.out.println(" Task " + taskName + " Started -----");
for(int i=0;i<input2 ;i++) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
System.out.println(" Task " + taskName + " Interrupted !! ");
e.printStackTrace();
}
input1 += i;
}
System.out.println(" Task " + taskName + " Completed ######");
return new CalcResult(input1) ;
}
}
public void test(){
ExecutorService taskExecutor = Executors.newFixedThreadPool(3);
CompletionService<CalcResult> taskCompletionService = new ExecutorCompletionService<CalcResult>(taskExecutor);
int submittedTasks = 5;
for (int i=0;i< submittedTasks;i++) {
taskCompletionService.submit(new CallableTask (
String.valueOf(i),
(i * 10),
((i * 10) + 10 )
));
System.out.println("Task " + String.valueOf(i) + "subitted");
}
for (int tasksHandled=0;tasksHandled<submittedTasks;tasksHandled++) {
try {
System.out.println("trying to take from Completion service");
Future<CalcResult> result = taskCompletionService.take();
System.out.println("result for a task availble in queue.Trying to get()");
// above call blocks till atleast one task is completed and results availble for it
// but we dont have to worry which one
// process the result here by doing result.get()
CalcResult l = result.get();
System.out.println("Task " + String.valueOf(tasksHandled) + "Completed - results obtained : " + String.valueOf(l.result));
} catch (InterruptedException e) {
// Something went wrong with a task submitted
System.out.println("Error Interrupted exception");
e.printStackTrace();
} catch (ExecutionException e) {
// Something went wrong with the result
e.printStackTrace();
System.out.println("Error get() threw exception");
}
}
}
}
Basically you use a CompletionService if you want to execute multiple tasks in parallel and then work with them in their completion order. So, if I execute 5 jobs, the CompletionService will give me the first one that that finishes. The example where there is only a single task confers no extra value over an Executor apart from the ability to submit a Callable.
I think the javadoc best answers the question of when the CompletionService is useful in a way an ExecutorService isn't.
A service that decouples the production of new asynchronous tasks from the consumption of the results of completed tasks.
Basically, this interface allows a program to have producers which create and submit tasks (and even examine the results of those submissions) without knowing about any other consumers of the results of those tasks. Meanwhile, consumers which are aware of the CompletionService could poll for or take results without being aware of the producers submitting the tasks.
For the record, and I could be wrong because it is rather late, but I am fairly certain that the sample code in that blog post causes a memory leak. Without an active consumer taking results out of the ExecutorCompletionService's internal queue, I'm not sure how the blogger expected that queue to drain.
First of all, if we do not want to waste processor time, we will not use
while (!future.isDone()) {
// Do some work...
}
We must use
service.shutdown();
service.awaitTermination(14, TimeUnit.DAYS);
The bad thing about this code is that it will shut down ExecutorService. If we want to continue work with it (i.e. we have some recursicve task creation), we have two alternatives: invokeAll or ExecutorService.
invokeAll will wait untill all tasks will be complete. ExecutorService grants us ability to take or poll results one by one.
And, finily, recursive example:
ExecutorService executorService = Executors.newFixedThreadPool(THREAD_NUMBER);
ExecutorCompletionService<String> completionService = new ExecutorCompletionService<String>(executorService);
while (Tasks.size() > 0) {
for (final Task task : Tasks) {
completionService.submit(new Callable<String>() {
#Override
public String call() throws Exception {
return DoTask(task);
}
});
}
try {
int taskNum = Tasks.size();
Tasks.clear();
for (int i = 0; i < taskNum; ++i) {
Result result = completionService.take().get();
if (result != null)
Tasks.add(result.toTask());
}
} catch (InterruptedException e) {
// error :(
} catch (ExecutionException e) {
// error :(
}
}
See it by yourself at run time,try to implement both solutions (Executorservice and Completionservice) and you'll see how different they behave and it will be more clear on when to use one or the other.
There is an example here if you want http://rdafbn.blogspot.co.uk/2013/01/executorservice-vs-completionservice-vs.html
Let's say you have 5 long running task(callable task) and you have submitted those task to executer service. Now imagine you don't want to wait for all 5 task to compete instead you want to do some sort of processing on these task if any one completes. Now this can be done either by writing polling logic on future objects or use this API.
package com.barcap.test.test00;
import java.util.concurrent.*;
/**
* Created by Sony on 25-04-2019.
*/
public class ExecutorCompletest00 {
public static void main(String[] args) {
ExecutorService exc= Executors.newFixedThreadPool( 10 );
ExecutorCompletionService executorCompletionService= new ExecutorCompletionService( exc );
for (int i=1;i<10;i++){
Task00 task00= new Task00( i );
executorCompletionService.submit( task00 );
}
for (int i=1;i<20;i++){
try {
Future<Integer> future= (Future <Integer>) executorCompletionService.take();
Integer inttest=future.get();
System.out.println(" the result of completion service is "+inttest);
break;
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
=======================================================
package com.barcap.test.test00;
import java.util.*;
import java.util.concurrent.*;
/**
* Created by Sony on 25-04-2019.
*/
public class ExecutorServ00 {
public static void main(String[] args) {
ExecutorService executorService=Executors.newFixedThreadPool( 9 );
List<Future> futList= new ArrayList <>( );
for (int i=1;i<10;i++) {
Future result= executorService.submit( new Task00( i ) );
futList.add( result );
}
for (Future<Integer> futureEach :futList ){
try {
Integer inm= futureEach.get();
System.out.println("the result of future executorservice is "+inm);
break;
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
===========================================================
package com.barcap.test.test00;
import java.util.concurrent.*;
/**
* Created by Sony on 25-04-2019.
*/
public class Task00 implements Callable<Integer> {
int i;
public Task00(int i) {
this.i = i;
}
#Override
public Integer call() throws Exception {
System.out.println(" the current thread is "+Thread.currentThread().getName() +" the result should be "+i);
int sleepforsec=100000/i;
Thread.sleep( sleepforsec );
System.out.println(" the task complted for "+Thread.currentThread().getName() +" the result should be "+i);
return i;
}
}
======================================================================
difference of logs for executor completion service:
the current thread is pool-1-thread-1 the result should be 1
the current thread is pool-1-thread-2 the result should be 2
the current thread is pool-1-thread-3 the result should be 3
the current thread is pool-1-thread-4 the result should be 4
the current thread is pool-1-thread-6 the result should be 6
the current thread is pool-1-thread-5 the result should be 5
the current thread is pool-1-thread-7 the result should be 7
the current thread is pool-1-thread-9 the result should be 9
the current thread is pool-1-thread-8 the result should be 8
the task complted for pool-1-thread-9 the result should be 9
teh result is 9
the task complted for pool-1-thread-8 the result should be 8
the task complted for pool-1-thread-7 the result should be 7
the task complted for pool-1-thread-6 the result should be 6
the task complted for pool-1-thread-5 the result should be 5
the task complted for pool-1-thread-4 the result should be 4
the task complted for pool-1-thread-3 the result should be 3
the task complted for pool-1-thread-2 the result should be 2
the current thread is pool-1-thread-1 the result should be 1
the current thread is pool-1-thread-3 the result should be 3
the current thread is pool-1-thread-2 the result should be 2
the current thread is pool-1-thread-5 the result should be 5
the current thread is pool-1-thread-4 the result should be 4
the current thread is pool-1-thread-6 the result should be 6
the current thread is pool-1-thread-7 the result should be 7
the current thread is pool-1-thread-8 the result should be 8
the current thread is pool-1-thread-9 the result should be 9
the task complted for pool-1-thread-9 the result should be 9
the task complted for pool-1-thread-8 the result should be 8
the task complted for pool-1-thread-7 the result should be 7
the task complted for pool-1-thread-6 the result should be 6
the task complted for pool-1-thread-5 the result should be 5
the task complted for pool-1-thread-4 the result should be 4
the task complted for pool-1-thread-3 the result should be 3
the task complted for pool-1-thread-2 the result should be 2
the task complted for pool-1-thread-1 the result should be 1
the result of future is 1
=======================================================
for executorservice the result will only be avialable after all tasks complted.
executor completionservice any result avilable make that return.
If the task producer is not interested in the results and it is another component's responsibility to process results of asynchronous task executed by executor service, then you should use CompletionService. It helps you in separating task result processor from task producer. See example http://www.zoftino.com/java-concurrency-executors-framework-tutorial
there is another advantage of using completionservice: Performance
when you call future.get(), you are spin waiting:
from java.util.concurrent.CompletableFuture
private Object waitingGet(boolean interruptible) {
Signaller q = null;
boolean queued = false;
int spins = -1;
Object r;
while ((r = result) == null) {
if (spins < 0)
spins = (Runtime.getRuntime().availableProcessors() > 1) ?
1 << 8 : 0; // Use brief spin-wait on multiprocessors
else if (spins > 0) {
if (ThreadLocalRandom.nextSecondarySeed() >= 0)
--spins;
}
when you have a long-running task, this will be a disaster for performance.
with completionservice, once the task is done, it's result will be enqueued and you can poll the queue with lower performance overhand.
completionservice achieve this by using wrap task with a done hook.
java.util.concurrent.ExecutorCompletionService
private class QueueingFuture extends FutureTask<Void> {
QueueingFuture(RunnableFuture<V> task) {
super(task, null);
this.task = task;
}
protected void done() { completionQueue.add(task); }
private final Future<V> task;
}
assuming you execute a tasks in parallel and you save the Future results in a list:
The practical main difference between ExecutorService and CompletionService is:
ExecutorService get() will try to retrieve the results in the submitted order waiting for completion.
CompletionService take() + get() will try to retrieve the results in the completion order disregarding the submission order.
ExecutorCompletionService class implements CompletionService.
ExecutorCompletionService returns futures objects based on completion order, so whichever task executes first, will be returned first. You just need to call executorCompletionService.take() to get completed Future object.
I found a blog that clear my thought.
java2blog link with example

Categories

Resources