Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I use Callable threads without ExecutorService?

Tags:

Can I use Callable threads without ExecutorService? We can use instances of Runnable and subclasses of Thread without ExecutorService and this code works normally. But this code works consistently:

public class Application2 {      public static class WordLengthCallable implements Callable {         public static int count = 0;         private final int numberOfThread = count++;          public Integer call() throws InterruptedException {             int sum = 0;             for (int i = 0; i < 100000; i++) {                sum += i;             }             System.out.println(numberOfThread);             return numberOfThread;        }    }    public static void main(String[] args) throws InterruptedException {        WordLengthCallable wordLengthCallable1 = new WordLengthCallable();        WordLengthCallable wordLengthCallable2 = new WordLengthCallable();        WordLengthCallable wordLengthCallable3 = new WordLengthCallable();        WordLengthCallable wordLengthCallable4 = new WordLengthCallable();        wordLengthCallable1.call();        wordLengthCallable2.call();        wordLengthCallable3.call();        wordLengthCallable4.call();        try {            Thread.sleep(1000);        } catch (InterruptedException e) {           e.printStackTrace();       }       System.exit(0);   } } 

With ExecutorService the code works with few threads. Where are my mistakes?

like image 874
user3233853 Avatar asked Aug 10 '14 17:08

user3233853


People also ask

Can I use Callable with thread?

Note that a thread can't be created with a Callable, it can only be created with a Runnable. Another difference is that the call() method can throw an exception whereas run() cannot.

Why do we need ExecutorService in Java?

The ExecutorService helps in maintaining a pool of threads and assigns them tasks. It also provides the facility to queue up tasks until there is a free thread available if the number of tasks is more than the threads available.

How do you call a Callable thread?

Each thread invokes the call() method, generates a random number, and returns it. The get() method is used to receive the returned random number object obtained from the different threads to the main thread. The get() method is declared in the Future interface and implemented in the FutureTask class.

Is Callable a functional interface?

Interface Callable<V>This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference. A task that returns a result and may throw an exception. Implementors define a single method with no arguments called call .


2 Answers

While interfaces are often created with an intended use case, they are never restricted to be used in that way.

Given a Runnable you can submit it to an ExecutorService, or pass it to the constructor of Thread or you can invoke its run() method directly like you can invoke any interface method without multi-threading involved. And there are more use cases, e.g. AWT EventQueue.invokeLater(Runnable) so never expect the list to be complete.

Given a Callable, you have the same options, so it’s important to emphasize that, unlike your question suggests, invoking call() directly does not involve any multi-threading. It just executes the method like any other ordinary method invocation.

Since there is no constructor Thread(Callable) using a Callable with a Thread without an ExecutorService requires slightly more code:

FutureTask<ResultType> futureTask = new FutureTask<>(callable); Thread t=new Thread(futureTask); t.start(); // … ResultType result = futureTask.get(); // will wait for the async completion 
like image 76
Holger Avatar answered Oct 09 '22 12:10

Holger


The simple direct answer is that you need to use an ExecutorService if you want to use a Callable to create and run a background thread, and certainly if you want to obtain a Future object, or a collection of Futures. Without the Future, you would not be able to easily obtain the result returned from your Callable or easily catch Exceptions generated. Of course you could try to wrap your Callable in a Runnable, and then run that in a Thread, but that would beg the question of why, since by doing so you would lose much.


Edit
You ask in comment,

Do you mean like the code below, which works?

public class Application2 {     public static class WordLengthCallable implements Callable {     public static int count = 0;     private final int numberOfThread = count++;      public Integer call() throws InterruptedException {         int sum = 0;         for (int i = 0; i < 100000; i++) {             sum += i;         }         System.out.println(numberOfThread);         return numberOfThread;     } }     public static void main(String[] args) throws InterruptedException {         new Thread(new MyRunnable()).start();         new Thread(new MyRunnable()).start();         new Thread(new MyRunnable()).start();         new Thread(new MyRunnable()).start();         try {             Thread.sleep(1000);         } catch (InterruptedException e) {             e.printStackTrace();         }         System.exit(0);     }      public static class MyRunnable implements Runnable {          @Override         public void run() {             try {                 new WordLengthCallable().call();             } catch (InterruptedException e) {                 e.printStackTrace();             }         }     } } 

My reply: Yes. The code in the link "sort of" works. Yes, it creates background threads, but the results from the calculations performed in the Callables are being discarded, and all exceptions are being ignored. This is what I mean by "since by doing so you would lose much".


e.g.,

  ExecutorService execService = Executors.newFixedThreadPool(THREAD_COUNT);   List<Future<Integer>> futures = new ArrayList<>();   for (int i = 0; i < THREAD_COUNT; i++) {      futures.add(execService.submit(new WordLengthCallable()));   }   for (Future<Integer> future : futures) {      try {         System.out.println("Future result: " + future.get());      } catch (ExecutionException e) {         e.printStackTrace();      }   }    Thread.sleep(1000);   System.out.println("done!");   execService.shutdown(); 

Edit 2
Or if you want the results returned as they occur, use a CompletionService to wrap your ExecutorService, something I've never attempted before:

import java.util.Random; 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;  public class CompletionServiceExample {    public static class WordLengthCallable implements Callable<Integer> {       private Random random = new Random();        public Integer call() throws InterruptedException {          int sleepTime = (2 + random.nextInt(16)) * 500;          Thread.sleep(sleepTime);          return sleepTime;       }    }     private static final int THREAD_COUNT = 4;     public static void main(String[] args) throws InterruptedException {       ExecutorService execService = Executors.newFixedThreadPool(THREAD_COUNT);       CompletionService<Integer> completionService = new ExecutorCompletionService<>(             execService);        for (int i = 0; i < THREAD_COUNT; i++) {          completionService.submit(new WordLengthCallable());       }       execService.shutdown();        try {          while (!execService.isTerminated()) {             int result = completionService.take().get().intValue();             System.out.println("Result is: " + result);          }       } catch (ExecutionException e) {          e.printStackTrace();       }        Thread.sleep(1000);       System.out.println("done!");    } } 
like image 38
Hovercraft Full Of Eels Avatar answered Oct 09 '22 14:10

Hovercraft Full Of Eels