Search code examples
javaconcurrencyrunnablejava.util.concurrentcallable

Do callable executes sequentially?


Whenever i run my program implementing callable, i get the output in a sequential form.

Like, here is my program :

package com.handson;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class WorkSheet_1 implements Callable<String> {

    /**
     * @param args
     */
    private int id;
    static int count = 0;
    public static String test[] = { "a1" , "a2" , "a3" , "a4" , "a5" , "a6" , "a7" , "a8" ,
                                    "b1" , "b2" , "b3" , "b4" , "b5" , "b6" , "b7" , "b8" ,
                                    "c1" , "c2" , "c3" , "c4" , "c5" , "c6" , "c7" , "c8" ,
                                    "d1" , "d2" , "d3" , "d4" , "d5" , "d6" , "d7" , "d8" ,
                                    "e1" , "e2" , "e3" , "e4" , "e5" , "e6" , "e7" , "e8" ,
                                    "f1" , "f2" , "f3" , "f4" , "f5" , "f6" , "f7" , "f8" ,
                                    "g1" , "g2" , "g3" , "g4" , "g5" , "g6" , "g7" , "g8" ,
                                    "h1" , "h2" , "h3" , "h4" , "h5" , "h6" , "h7" , "h8"}; 
    public WorkSheet_1(int id){
        this.id = id;
    }

    public static void main(String[] args) {
        try{
        // TODO Auto-generated method stub
            BlockingQueue blockingQueue = new ArrayBlockingQueue<WorkSheet_1>(48);
            ThreadPoolExecutor testExecutor = new ThreadPoolExecutor(6, 10, 1, TimeUnit.SECONDS, blockingQueue);
            for(int i = 0 ;i < test.length ;i++){
                Future<String> testFuture = testExecutor.submit(new WorkSheet_1(i));
                try {
                    System.out.println("Output Returned is : "+testFuture.get());
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }catch(RejectedExecutionException e){
            e.printStackTrace();
        }
    }

    @Override
    public String call() throws Exception {
        // TODO Auto-generated method stub
        return "Called "+test[this.id];
    }



}

CALLABLE OUTPUT :

Output Returned is : Called a1
Output Returned is : Called a2
Output Returned is : Called a3
Output Returned is : Called a4
Output Returned is : Called a5
Output Returned is : Called a6
Output Returned is : Called a7
Output Returned is : Called a8
Output Returned is : Called b1
Output Returned is : Called b2
Output Returned is : Called b3
Output Returned is : Called b4
Output Returned is : Called b5
Output Returned is : Called b6
Output Returned is ...............

Output always prints the array sequentially whereas when i implement runnable output is in any order :

RUNNABLE OUTPUT :

Output Returned is : Called a1
Output Returned is : Called a3
Output Returned is : Called a7
Output Returned is : Called a8
Output Returned is : Called b1
Output Returned is : Called b2
Output Returned is : Called b3
Output Returned is : Called b4 ..............

Why such a difference ?


Solution

  • Using CompletionService we dont need to print Sysout in call function(as Provided by @Patricia) and there is a benefit of using CompletionService than Futures.

    For more info refer java-concurrency-executors-and-thread-pools. The site stated,

    "Code using future is bit complicated. And there is a disadvantage. If the first task takes a long time to compute and all the other tasks ends before the first, the current thread cannot compute the result before the first task ends.Solution for this problem is Completion Service"

    Now Solution using Sompletion Service print the desired result :

        BlockingQueue<Runnable> blockingQueue   blockingQueue = new ArrayBlockingQueue<WorkSheet_1>(48);
        ThreadPoolExecutor testExecutor = new ThreadPoolExecutor(6, 16, 1,
                TimeUnit.SECONDS, blockingQueue, new CustomThreadFactory());
    
        CompletionService<String> completionService = new ExecutorCompletionService<String>(
                testExecutor);
    
        for (int i = 0; i < test.length; i++) {
            completionService.submit(new WorkSheet_1(i));
        }
    
        for (int i = 0; i < test.length; i++) {
            try {
                String result = completionService.take().get();
                System.out.println("Output Returned is : " + result);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (ExecutionException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    
            // Compute the result
        }