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.
Related
I need a group of threads to run at the same time, and then another group of threads after that. For example, 10 threads start working, and then 10 or 15 other threads.
Of course, the first approach I've tried was to create a loop.
while (true) {
for (int i = 0; i < 10; i++) {
Thread thread = new Thread(
new Runnable() {
#Override
public void run() {
System.out.println("hi");
}
});
thread.start();
}
}
But the problem is when scenario like this happens: imagine if in first iteration, 8 threads finished their tasks, and 2 threads take longer time. The next 10 threads won't start until all 8 + 2 (completed and not completed) threads finish. while, I want an approach where 8 threads get replaced by 8 of waiting to start threads.
Bare Threads
It can be done using bare Thread and Runnable without diving into more advance technologies.
For that, you need to perform the following steps:
define your task (provide an implementation of the Runnable interface);
generate a collection of Threads creating based on this task);
start every thread;
invoke join() on every of these thread (note that firstly we need to start all threads).
That's how it might look like:
public static void main(String[] args) throws InterruptedException {
Runnable task = () -> System.out.println("hi");
int counter = 0;
while (true) {
System.out.println("iteration: " + counter++);
List<Thread> threads = new ArrayList<>();
for (int i = 0; i < 10; i++) {
threads.add(new Thread(task));
}
for (Thread thread : threads) {
thread.start();
}
for (Thread thread : threads) {
thread.join();
}
Thread.currentThread().sleep(1000);
}
}
Instead of managing your Threads manually, it definitely would be wise to look at the facilities provided by the implementations of the ExecutorService interfaces.
Things would be a bit earthier if you use Callable interface for your task instead of Runnable. Callable is more handy in many cases because it allows obtaining the result from the worker-thread and also propagating an exception if thing went wrong (as opposed run() would force you to catch every checked exception). If you have in mind something more interesting than printing a dummy message, you might find Callable to be useful for your purpose.
ExecutorService.invokeAll() + Callable
ExecutorService has a blocking method invokeAll() which expects a collection of the callable-tasks and return a list of completed Future objects when all the tasks are done.
To generate a light-weight collection of repeated elements (since we need to fire a bunch of identical tasks) we can use utility method Collections.nCopies().
Here's a sample code which repeatedly runs a dummy task:
ExecutorService executor = Executors.newWorkStealingPool();
while (true) {
executor.invokeAll(Collections.nCopies(10, () -> {
System.out.println("hi");
return true;
}));
}
To make sure that it does what expected, we can add a counter of iterations and display it on the console and Thread.currentThread().sleep() to avoid cluttering the output very fast (for the same reason, the number of tasks reduced to 3):
public static void main(String[] args) throws InterruptedException {
ExecutorService executor = Executors.newWorkStealingPool();
int counter = 0;
while (true) {
System.out.println("iteration: " + counter++);
executor.invokeAll(Collections.nCopies(3, () -> {
System.out.println("hi");
return true;
}));
Thread.currentThread().sleep(1000);
}
}
Output:
iteration: 0
hi
hi
hi
iteration: 1
hi
hi
hi
... etc.
CompletableFuture.allOf().join() + Runnable
Another possibility is to use CompletableFuture API, and it's method allOf() which expects a varargs of submitted tasks in the form CompletableFuture and return a single CompletableFuture which would be completed when all provided arguments are done.
In order to synchronize the execution of the tasks with the main thread, we need to invoke join() on the resulting CompletableFuture instance.
That's how it might be implemented:
public static void main(String[] args) throws InterruptedException {
ExecutorService executor = Executors.newWorkStealingPool();
Runnable task = () -> System.out.println("hi");
int counter = 0;
while (true) {
System.out.println("iteration: " + counter++);
CompletableFuture.allOf(
Stream.generate(() -> task)
.limit(3)
.map(t -> CompletableFuture.runAsync(t, executor))
.toArray(CompletableFuture<?>[]::new)
).join();
Thread.currentThread().sleep(1000);
}
}
Output:
iteration: 0
hi
hi
hi
iteration: 1
hi
hi
hi
... etc.
ScheduledExecutorService
I suspect you might interested in scheduling these tasks instead of running them reputedly. If that's the case, have a look at ScheduledExecutorService and it's methods scheduleAtFixedRate() and scheduleWithFixedDelay().
For adding tasks to threads and replacing them you can use ExecutorService. You can create it by using:
ExecutorService executor = Executors.newFixedThreadPool(10);
I have a loop which create a new Thread on each iteration, like so:
for(int i = 0; i < REPEAT; i++) {
new Thread(new MyTask(i)).start();
Thread.sleep(1);
}
private void finalTask() {
//Some code to be executed once every threads stopped running
}
Where MyTask is a class implementing Runnable. My goal is: I would like to run finalTask once every threads stopped. To achieve this, I have tried incrementing a variable by 1 each time a thread finished running, and once this variable was equal to REPEAT, the final task would run. But this didn't work. I've searched on Google and StackOverlow for answers to my problem, but there are very little informations on this and none of them worked as well. There would always be a thread that was running after the final task. How can I do this then?
You can use a CountDownLatch for this. A CountDownLatch is
A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.
CountDownLatch countDownLatch = new CountDownLatch(REPEAT);
for (int i = 0; i < REPEAT; i++) {
new Thread(new MyTask(i, countDownLatch)).start();
Thread.sleep(1);
}
finalTask(countDownLatch);
I create a CountDownLatch whose count is initialized to the value of REPEAT. I pass this to each of the threads and to the finalTask method.
Each thread after doing its work should call the countDown method of the countDownLatch.
private static class MyTask implements Runnable {
private int i;
private CountDownLatch countDownLatch;
private MyTask(int i, CountDownLatch countDownLatch) {
this.i = i;
this.countDownLatch = countDownLatch;
}
#Override
public void run() {
//Perform some task
System.out.println("Running " + i);
countDownLatch.countDown();
}
}
The first line of the finalTask method should call the await method of the CountDownLatch. This will cause the thread running the finalTask wait till the count of the CountDownLatch reaches 0 i.e., until all threads (REPEAT number of them) has completed and invoked the countDown of the CountDownLatch.
private static void finalTask(CountDownLatch countDownLatch) {
try {
countDownLatch.await(); //this will wait until the count becomes 0.
} catch (InterruptedException e) {
e.printStackTrace(); //handle it appropriately
}
//Some code to be executed once all threads stopped running
System.out.println("All done");
}
Another simple way is to just join() on all the threads and then call finalTask():
Thread tasks[] = new Thread[REPEAT];
for(int i = 0; i < REPEAT; i++) {
tasks[i] = new Thread(new MyTask(i));
tasks[i].start();
}
for (Thread task : tasks) {
for (;;) {
try {
task.join();
break;
}
catch ( InterruptedException e ) {
// catch code here
}
}
}
finalTask();
Note there's almost more code used to handle the possible InterruptedException from the join() method call than used to implement the rest of the processing.
You can put them into CompletableFutures and then use whenComplete() .
CompletableFuture[] all =
IntStream.range(0, REPEAT+1).
.mapToObj(i -> CompletableFuture.supplyAsync(new MyTask(i)))
.toArray(CompletableFuture[]::new) ;
CompletableFuture.allOf(all).whenComplete((r, t) -> {
// your code here
}) ;
I want to know that when a program waits for Future object of one thread, will other threads continue their execution.
I have tried the below sample, it seems when my program is waiting for one thread, other threads are not continuing their execution. Please tell me whether this is correct or is there any issues with my code for handling threads.
ExecutorService executor = Executors.newFixedThreadPool(3);
for(int i=0; i<5 ;i++)
{
Worker w = new Worker();
Future<String> future = executor.submit(w);
while(!future.isDone())
{
//Wait
}
String s = future.get();
System.out.println(LocalDateTime.now()+" "+s);
}
executor.shutdown();
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
Below is my worker class:
public class Worker implements Callable<String> {
#Override
public String call() throws Exception {
// TODO Auto-generated method stub
Thread.sleep(3000);
return Thread.currentThread().getName();
}
}
I am getting the below results(Added date time to show that the results are not parallel):
2019-01-04T16:34:22.647 pool-1-thread-1
2019-01-04T16:34:25.661 pool-1-thread-2
2019-01-04T16:34:28.673 pool-1-thread-3
2019-01-04T16:34:31.685 pool-1-thread-1
2019-01-04T16:34:34.699 pool-1-thread-2
The problem
You presented the code which from main thread perspective waits (2) for each execution before submitting new task (1). In other words: in main thread you submit the task, wait for complete execution in main thread and submit next task after.
ExecutorService executor = Executors.newFixedThreadPool(3);
for(int i=0; i<5 ;i++)
{
Worker w = new Worker();
Future<String> future = executor.submit(w); // (1)
while(!future.isDone()) // (2)
{
//Wait
}
String s = future.get();
System.out.println(LocalDateTime.now()+" "+s);
}
executor.shutdown();
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
Solution
To solve the issue you should (from main thread perspective) submit all tasks without waiting and then wait for results from executor service.
Example: https://stackoverflow.com/a/49746114/1815881
You can construct all tasks then call invokeAll() in ExecutorService.
I would like to run thread one after another.
Is there any alternative way to Marathon with Java 8?
Without using ExecuterService:
public class Marathon {
public static void main(String[] args) throws InterruptedException {
Runnable task = () -> {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+ " is running... " + i);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
}
};
Thread t1 = new Thread(task, "Mary");
Thread t2 = new Thread(task, "David");
t1.start();
t1.join(100);
t2.start();
}
}
Output:
Mary is running... 0
David is running... 0
Mary is running... 1
David is running... 1
...
Following code doesn't work as Marathon :
public class Marathon2 {
public static void main(String[] args)
throws InterruptedException, ExecutionException, TimeoutException {
ExecutorService service = null;
Runnable task = () -> {
try {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()
+ " is running... " + i);
}
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
}
};
try {
service = Executors.newFixedThreadPool(4);
Future<?> job1 = service.submit(task);
job1.get(500, TimeUnit.MILLISECONDS);
Future<?> job2 = service.submit(task);
} finally {
if (service != null)
service.shutdown();
}
}
}
Output:
pool-1-thread-1 is running... 0
...
pool-1-thread-1 is running... 9
pool-1-thread-2 is running... 0
...
pool-1-thread-2 is running... 9
Is it possible to do with ExecuterService?
Expected:
pool-1-thread-1 is running... 0
pool-1-thread-2 is running... 0
...
pool-1-thread-1 is running... 9
pool-1-thread-2 is running... 9
Without dealing with any threads nor with Executors directly you can do it with a CompletableFuture
Runnable runnable = () -> System.out.println("hi");
Runnable runnable1 = () -> System.out.println("there");
CompletableFuture<Void> all = CompletableFuture.runAsync(runnable).thenRun(runnable1);
all.whenComplete((x,th) -> {
System.out.println("both done");
});
Note that this would use the common ForkJoin pool but you can still provide your own.
The two classes are not doing the same thing. You can probably reach the solution yourself by comparing them closely. First, do you know exactly how your first class (Marathon) works? In particular, what do you think the following line does?
t1.join(100);
The thread t1, which has just started running, has just gone into a loop which counts up once every 200 milliseconds. The join(100) call simply causes the current (main) thread to wait 100 milliseconds. You will achieve exactly the same results by replacing that line with this one:
Thread.sleep(100);
Now that the main thread has slept for 100 milliseconds, it starts thread t2. Now the two threads are running in parallel, and every 200 milliseconds both threads output a line, the second thread delayed by 100 milliseconds so that they appear evenly interleaved.
Now let's look at your second method, Marathon2. A few differences from the first class are immediately obvious:
The sleep in the Runnable is outside the loop, instead of inside.
The sleep in the Runnable is only 100 milliseconds, instead of 200.
The maximum wait in the main thread is 500 milliseconds, instead of 100.
The Future.get method causes a TimeoutException instead of just continuing. We can simply replace this call with a sleep anyway, since that's all that the first class does.
So, ironing out the differences, we get the following Marathon2 class which behaves in a similar manner to the other class (Marathon), with interleaved threads:
public class Marathon2 {
public static void main(String[] args)
throws InterruptedException, ExecutionException, TimeoutException {
ExecutorService service = null;
Runnable task = () -> {
try {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()
+ " is running... " + i);
TimeUnit.MILLISECONDS.sleep(200);
}
} catch (InterruptedException e) {
}
};
try {
service = Executors.newFixedThreadPool(4);
Future<?> job1 = service.submit(task);
TimeUnit.MILLISECONDS.sleep(100);
Future<?> job2 = service.submit(task);
} finally {
if (service != null)
service.shutdown();
}
}
}
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