Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ExecutorService vs Casual Thread Spawner

Tags:

I have a basic question about how ExecutorService works in Java.

It is quite hard to see the difference between simply creating Threads to perform some tasks in parallel and assigning each tasks to the ThreadPool.

The ExecutorService also looks very simple and efficient to use, so I was wondering why we don't use it all the time.

Is it just a matter of one way executing its job faster than the other ?

Here's two very simple examples to show the difference between the two ways :

Using executor service: Hello World (task)

static class HelloTask implements Runnable {     String msg;      public HelloTask(String msg) {         this.msg = msg;      }     public void run() {         long id = Thread.currentThread().getId();         System.out.println(msg + " from thread:" + id);     } } 

Using executor service: Hello World (creating executor, submitting)

static class HelloTask {     public static void main(String[] args) {         int ntasks = 1000;         ExecutorService exs = Executors.newFixedThreadPool(4);          for (int i=0; i<ntasks; i++) {              HelloTask t = new HelloTask("Hello from task " + i);                 exs.submit(t);         }         exs.shutdown();     } } 

the following shows a similar example but extending the Callable interface, could you tell me the difference between the two and in which cases one should use a specific one instead of the other ?

Using executor service: Counter (task)

static class HelloTaskRet implements Callable<Long> {     String msg;      public HelloTaskRet(String msg) {         this.msg = msg; }          public Long call() {         long tid = Thread.currentThread().getId();          System.out.println(msg + " from thread:" + tid);          return tid;     }  } 

Using executor service: (creating, submitting)

static class HelloTaskRet {     public static void main(String[] args) {         int ntasks = 1000;         ExecutorService exs = Executors.newFixedThreadPool(4);          Future<Long>[] futures = (Future<Long>[]) new Future[ntasks];          for (int i=0; i<ntasks; i++) {              HelloTaskRet t = new HelloTaskRet("Hello from task " + i);             futures[i] = exs.submit(t);         }         exs.shutdown();     } } 
like image 383
Philippe Avatar asked Nov 14 '14 20:11

Philippe


People also ask

What are the advantages of using ExecutorService instead of creating threads directly?

ExecutorService abstracts away many of the complexities associated with the lower-level abstractions like raw Thread . It provides mechanisms for safely starting, closing down, submitting, executing, and blocking on the successful or abrupt termination of tasks (expressed as Runnable or Callable ).

What is difference between ExecutorService and ForkJoinPool?

The Fork/Join framework in Java 7 is an implementation of the Divide and Conquer algorithm, in which a central ForkJoinPool executes branching ForkJoinTasks. ExecutorService is an Executor that provides methods to manage the progress-tracking and termination of asynchronous tasks.

Is ExecutorService a thread?

The Java ExecutorService is a construct that allows you to pass a task to be executed by a thread asynchronously. The executor service creates and maintains a reusable pool of threads for executing submitted tasks.

What are Executor and ExecutorService and what are the differences between them?

Executor just executes stuff you give it. ExecutorService adds startup, shutdown, and the ability to wait for and look at the status of jobs you've submitted for execution on top of Executor (which it extends). This is a perfect answer, short and clear.


2 Answers

While the question and the sample code do not correlate, I'll try clarifying both. The advantage of ExecutorService over haphazardly spawning threads is that it behaves predictably and avoids the overhead of thread creation, which is relatively big on the JVM (it needs to reserve memory for each thread, for example). By predictability, at least for the fixedThreadPool, I mean you know the maximum number of concurrent threads, and you know when and how they might get created (so your JVM won't blow up in case of sudden peaks).

By Vince Emigh: ExecutorService also supports cachedThreadPool, which doesn't have a max. The main reason people choose to use ExecutorService is to prevent the overhead of creating multiple threads (by using worker threads). It's mostly used in cases where many small tasks need to be executed on a separate thread. Also, don't forget about singleThreadExecutor.

Now, on the topic of Runnable vs Callable, it is easy to see from your examples. Callables can return a value place-holder (Future) that will eventually be populated by an actual value in the future. Runnables can not return anything.

By Vince Emigh: Runnable also cannot throw exceptions, while Callable can.

like image 97
kaqqao Avatar answered Sep 24 '22 13:09

kaqqao


ExecutorService provides many advantages compared to plain threads

  1. You can create/manage/control life cycle of Threads & optimize thread creation cost overheads
  2. You can control processing of tasks ( Work Stealing, ForkJoinPool, invokeAll) etc.
  3. You can schedule tasks in Future time
  4. You can monitor the progress and health of threads

Even for a single Thread, I prefer to use Executors.newFixedThreadPool(1);

Have a look at related SE questions:

Java's Fork/Join vs ExecutorService - when to use which?

What are the advantages of using an ExecutorService?

like image 34
Ravindra babu Avatar answered Sep 23 '22 13:09

Ravindra babu