0

Basically something like this:

ExecutorService service = Executors.newFixedThreadPool(2);

Future<Boolean> futureFoo = service.submit(myFooTask);
Future<Boolean> futureBar = service.submit(myBarTask);

int resultFoo;
boolean resultBar;
resultFoo = futureFoo.get();
resultBar = futureBar.get();

I want to do an event to manage independently the first result I get, without waiting for futureFoo to finish first.

Mauricio Pastorini
  • 762
  • 2
  • 11
  • 24
  • 1
    Possible duplicate of [Java executors: how to be notified, without blocking, when a task completes?](https://stackoverflow.com/questions/826212/java-executors-how-to-be-notified-without-blocking-when-a-task-completes) – Felix Jun 15 '17 at 23:38
  • 2
    If you have java8, you can look at the `CompletableFuture`: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html – Nim Jun 15 '17 at 23:53
  • 1
    Why? The whole point of `Future` is that you don't do the `get()` until you _need_ the result. If you need both results before you can proceed, then it won't matter what order you get them in. If you need one of them before you need the other one, then do the get() for the first one just at the point where you can go no further without it. – Solomon Slow Jun 16 '17 at 03:07
  • The thing is that I want performance, so I dont want to wai the first `get()` if the second `get()` result is in an incorrect state. – Mauricio Pastorini Jun 16 '17 at 12:18
  • This is really 2 questions. The real answer that matches the title and the question is the CompletionService answer below. If you then ask another question you've screwed up this question/answer for posterity. – Gray Jun 16 '17 at 22:13

2 Answers2

2

you can use CompletionService. The results of the callables are put in a queue, and you can take the results of the tasks as soon as they complete.

in this case, you don't need to wait for the results of Foo if Bar completes earlier.

for example:

import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

public class CompletionServiceExample {


    private static Logger LOGGER = Logger.getLogger("CompletionServiceExample");

    public static void main(String[] args) throws InterruptedException {

        CompletionServiceExample completionServiceExample = new CompletionServiceExample();
        completionServiceExample.doTheWork();
    }

    private void doTheWork() throws InterruptedException {

        final ExecutorService executorService = Executors.newFixedThreadPool(2);
        final CompletionService<Boolean> completionService = new ExecutorCompletionService<>(executorService);


        completionService.submit(new Foo());
        completionService.submit(new Bar());

        int total_tasks = 2;

        for(int i = 0; i < total_tasks; ++i) {

            try {
                final Future<Boolean> value = completionService.take();
                System.out.println("received value: " + value.get());
            } catch (ExecutionException e) {
                LOGGER.log(Level.WARNING, "Error while processing task. ", e);
            } catch (InterruptedException e) {
                LOGGER.log(Level.WARNING, "interrupted while waiting for result", e);
            }
        }


        executorService.shutdown();
        executorService.awaitTermination(5, TimeUnit.SECONDS);

    }
}

class Foo implements Callable<Boolean> {

    @Override
    public Boolean call() throws Exception {
        Thread.sleep(5000);
        return true;
    }
}

class Bar implements Callable<Boolean> {

    @Override
    public Boolean call() throws Exception {
        Thread.sleep(1000);
        return false;
    }
}
Jose Zevallos
  • 685
  • 4
  • 3
  • This is really close of what I am looking for. The thing is that what about If I want to return different types in Foo and Bar results? How can I do the: `final Future value = completionService.take();` – Mauricio Pastorini Jun 16 '17 at 12:25
  • I replied in a separate answer because I wanted to include sample code – Jose Zevallos Jun 16 '17 at 13:06
1

If you want to return different types, you can use a base class and do downcasting. for example like this:

import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

public class CompletionServiceExample {


    private static Logger LOGGER = Logger.getLogger("CompletionServiceExample");

    public static void main(String[] args) throws InterruptedException {

        CompletionServiceExample completionServiceExample = new CompletionServiceExample();
        completionServiceExample.doTheWork();
    }

    private void doTheWork() throws InterruptedException {

        final ExecutorService executorService = Executors.newFixedThreadPool(2);
        final CompletionService<Base> completionService = new ExecutorCompletionService<>(executorService);


        completionService.submit(new FooBase());
        completionService.submit(new BarBase());

        int total_tasks = 2;

        for (int i = 0; i < total_tasks; ++i) {

            try {
                final Future<Base> value = completionService.take();
                Base base = value.get();
                if (base instanceof FooBase) {
                    int myInteger = ((FooBase) base).getValue();
                    System.out.println("received value: " + myInteger);
                }
                if (base instanceof BarBase) {
                    boolean myBoolean = ((BarBase) base).isValue();
                    System.out.println("received value: " + myBoolean);
                }

            } catch (ExecutionException e) {
                LOGGER.log(Level.WARNING, "Error while processing task. ", e);
            } catch (InterruptedException e) {
                LOGGER.log(Level.WARNING, "interrupted while waiting for result", e);
            }
        }


        executorService.shutdown();
        executorService.awaitTermination(5, TimeUnit.SECONDS);

    }
}

class Base {
}

class FooBase extends Base implements Callable<Base> {

    private int value;

    @Override
    public Base call() throws Exception {
        Thread.sleep(5000);
        value = 10;
        return this;
    }

    public int getValue() {
        return value;
    }
}

class BarBase extends Base implements Callable<Base> {

    private boolean value;

    @Override
    public Base call() throws Exception {
        Thread.sleep(1000);
        value = false;
        return this;
    }

    public boolean isValue() {
        return value;
    }
}
Jose Zevallos
  • 685
  • 4
  • 3