Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java- Using invokeAll to get future results in order but only for some threads

I...really don't know how to word the title better. But basically, what I have is a thread pool with all these threads busily working. I want them to report their results in the order that they were assigned, but at the same time, I want to work in batches. To illustrate, and example would be

ExecutorService exec = Executors.newFixedThreadPool(8);

class MyCallable implements Callable<byte[]> {
    private final int threadnumber;

    MyCallable(int threadnumber){
        this.threadnumber = threadnumber;
    }

    public byte[] call() {
        //does something
    }
}
List<Callable<byte[]>> callables = new ArrayList<Callable<byte[]>>();

for(int i=1; i<=20; i++) {
    callables.add(new MyCallable(i));
}
try {
    List<Future<byte[]>> results = exec.invokeAll(callables);
    for(Future<byte[]> result: results) {
            System.out.write(result.get(), 0, result.get().length);
    }

Basically, the pool thread has 8 threads and I end up having 20 tasks (these are just examples). The way this works now, if I understand correctly, is that it waits until ALL 20 tasks are done before outputting them in order (from 1 to 20). What this program is supposed to do is output a continuous stream of bytes (which were processed by threads, and since I need to keep the order intact, I used the future interface). While I don't mind waiting until all 20 tasks are done, is there anyway so that the threads simply output in order as they go.

If there's no way or I'm just completely misunderstanding how invokeAll works, clarification there is welcome too. Thanks a bunch in advance! Executors are a bit confusing since I only just learned about them.

Random addendum, am I even allowed to return a byte array from a callable?

like image 462
T T Avatar asked Feb 19 '23 16:02

T T


2 Answers

invokeAll() waits until all results are computed before it returns.

Use a loop and submit() them one by one instead, this method returns a Future with the pending result immediately:

...
for(int i=1; i<=20; i++) {
    results.add(exec.submit(new MyCallable(i))); 
}
try {
    for(Future<Integer> result: results) {
            System.out.write(result.get(), 0, result.get().length);
    }
}
...
like image 137
Keppil Avatar answered Feb 21 '23 06:02

Keppil


Using invokeAll also you can achieve.

 List<Future<byte[]>> results = exec.invokeAll(callables); 

It will return the future object list.

ThreadPoll will execute the tasks in random order . Task execution order cannnot be controlled.

Future Object

  1. Its a reference of task which is submitted in ThreadPool.

  2. It has a method get(). Its a blocking call method. If you invoke the get() method ,call will be wait until tasks get completed.

How to ensure Tasks submission order

Results order is same in callables order. Even thread pool will execute in different order we can retrieve in same order.

For Ex .

Three Tasks 1,2,3

1 & 3 --> Completed.

2 ------> Taking long time to execute.

After calling invokeAll method It will return List of Future in same order.

Task 1 : Future#get method return result since its already completed

Task 2 : Future#get method waits till task will complete.

Iteration waits till second task will complete even though third task completed. It wont get result from third thread.

like image 42
Siva Kumar Avatar answered Feb 21 '23 05:02

Siva Kumar