What are the advantages of using an ExecutorService?
Asked Answered
S

9

58

What is the advantage of using ExecutorService over running threads passing a Runnable into the Thread constructor?

Subacute answered 21/10, 2010 at 3:31 Comment(0)
S
54

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).

From JCiP, Section 6.2, straight from the horse's mouth:

Executor may be a simple interface, but it forms the basis for a flexible and powerful framework for asynchronous task execution that supports a wide variety of task execution policies. It provides a standard means of decoupling task submission from task execution, describing tasks as Runnable. The Executor implementations also provide lifecycle support and hooks for adding statistics gathering, application management, and monitoring. ... Using an Executor is usually the easiest path to implementing a producer-consumer design in your application.

Rather than spending your time implementing (often incorrectly, and with great effort) the underlying infrastructure for parallelism, the j.u.concurrent framework allows you to instead focus on structuring tasks, dependencies, potential parallelism. For a large swath of concurrent applications, it is straightforward to identify and exploit task boundaries and make use of j.u.c, allowing you to focus on the much smaller subset of true concurrency challenges which may require more specialized solutions.

Also, despite the boilerplate look and feel, the Oracle API page summarizing the concurrency utilities includes some really solid arguments for using them, not least:

Developers are likely to already understand the standard library classes, so there is no need to learn the API and behavior of ad-hoc concurrent components. Additionally, concurrent applications are far simpler to debug when they are built on reliable, well-tested components.

Java concurrency in practice is a good book on concurrency. If you haven't already, get yourself a copy. The comprehensive approach to concurrency presented there goes well beyond this question, and will save you a lot of heartache in the long run.

Singly answered 21/10, 2010 at 3:38 Comment(1)
what does "decoupling task submission from task execution" means in the context of Thread class in javaKaterinekates
S
20

An advantage I see is in managing/scheduling several threads. With ExecutorService, you don't have to write your own thread manager which can be plagued with bugs. This is especially useful if your program needs to run several threads at once. For example you want to execute two threads at a time, you can easily do it like this:

ExecutorService exec = Executors.newFixedThreadPool(2);

exec.execute(new Runnable() {
  public void run() {
    System.out.println("Hello world");
  }
});

exec.shutdown();

The example may be trivial, but try to think that the "hello world" line consists of a heavy operation and you want that operation to run in several threads at a time in order to improve your program's performance. This is just one example, there are still many cases that you want to schedule or run several threads and use ExecutorService as your thread manager.

For running a single thread, I don't see any clear advantage of using ExecutorService.

Suzannsuzanna answered 21/10, 2010 at 3:39 Comment(5)
Isn't it exec.execute(new Runnable().. ?Subacute
Either is okay since Thread implements Runnable. For simple cases, Runnable should be adequate.Suzannsuzanna
I really don't think there's any point in creating a Thread when all you need is a Runnable... you aren't even starting the Thread, so it only adds confusion and unnecessary baggage.Nonperishable
ayt, applied review comment. :)Suzannsuzanna
It's always good practice to do exec.shutdown(); in finally statement with a null check.Iceland
T
15

The following limitations from traditional Thread overcome by Executor framework(built-in Thread Pool framework).

  • Poor Resource Management i.e. It keep on creating new resource for every request. No limit to creating resource. Using Executor framework we can reuse the existing resources and put limit on creating resources.
  • Not Robust : If we keep on creating new thread we will get StackOverflowException exception consequently our JVM will crash.
  • Overhead Creation of time : For each request we need to create new resource. To creating new resource is time consuming. i.e. Thread Creating > task. Using Executor framework we can get built in Thread Pool.

Benefits of Thread Pool

  • Use of Thread Pool reduces response time by avoiding thread creation during request or task processing.

  • Use of Thread Pool allows you to change your execution policy as you need. you can go from single thread to multiple thread by just replacing ExecutorService implementation.

  • Thread Pool in Java application increases stability of system by creating a configured number of threads decided based on system load and available resource.

  • Thread Pool frees application developer from thread management stuff and allows to focus on business logic.

Source

Tomasine answered 19/12, 2015 at 11:21 Comment(0)
A
8

Below are some benefits:

  1. Executor service manage thread in asynchronous way
  2. Use Future callable to get the return result after thread completion.
  3. Manage allocation of work to free thread and resale completed work from thread for assigning new work automatically
  4. fork - join framework for parallel processing
  5. Better communication between threads
  6. invokeAll and invokeAny give more control to run any or all thread at once
  7. shutdown provide capability for completion of all thread assigned work
  8. Scheduled Executor Services provide methods for producing repeating invocations of runnables and callables Hope it will help you
Alcala answered 1/7, 2013 at 8:1 Comment(2)
Isn't it a "Future" in second point instead of Callable ? Future is from where we can retrieve result/Value after thread completion.Georgie
Yes like for eg. Future<String> future = executorService.submit(callable);Athenaathenaeum
A
4

Is it really that expensive to create a new thread?

As a benchmark, I just created 60,000 threads with Runnables with empty run() methods. After creating each thread, I called its start(..) method immediately. This took about 30 seconds of intense CPU activity. Similar experiments have been done in response to this question. The summary of those is that if the threads do not finish immediately, and a large number of active threads accumulate (a few thousand), then there will be problems: (1) each thread has a stack, so you will run out of memory, (2) there might be a limit on the number of threads per process imposed by the OS, but not necessarily, it seems.

So, as far as I can see, if we're talking about launching say 10 threads per second, and they all finish faster than new ones start, and we can guarantee that this rate won't be exceeded too much, then the ExecutorService doesn't offer any concrete advantage in visible performance or stability. (Though it may still make it more convenient or readable to express certain concurrency ideas in code.) On the other hand, if you might be scheduling hundreds or thousands of tasks per second, which take time to run, you could run into big problems straight away. This might happen unexpectedly, e.g. if you create threads in response to requests to a server, and there is a spike in the intensity of requests that your server receives. But e.g. one thread in response to every user input event (key press, mouse motion) seems to be perfectly fine, as long as the tasks are brief.

Azevedo answered 27/2, 2016 at 9:16 Comment(0)
V
3

ExecutorService also gives access to FutureTask which will return to the calling class the results of a background task once completed. In the case of implementing Callable

public class TaskOne implements Callable<String> {

@Override
public String call() throws Exception {
    String message = "Task One here. . .";
    return message;
    }
}

public class TaskTwo implements Callable<String> {

@Override
public String call() throws Exception {
    String message = "Task Two here . . . ";
    return message;
    }
}

// from the calling class

ExecutorService service = Executors.newFixedThreadPool(2);
    // set of Callable types
    Set<Callable<String>>callables = new HashSet<Callable<String>>();
    // add tasks to Set
    callables.add(new TaskOne());
    callables.add(new TaskTwo());
    // list of Future<String> types stores the result of invokeAll()
    List<Future<String>>futures = service.invokeAll(callables);
    // iterate through the list and print results from get();
    for(Future<String>future : futures) {
        System.out.println(future.get());
    }
Virgenvirgie answered 11/6, 2015 at 12:19 Comment(0)
H
2

Prior to java 1.5 version, Thread/Runnable was designed for two separate services

  1. Unit of work
  2. Execution of that unit of work

ExecutorService decouples those two services by designating Runnable/Callable as unit of work and Executor as a mechanism to execute ( with lifecycling) the unit of work

Hogue answered 13/2, 2015 at 4:59 Comment(0)
N
1

Executor Framework

//Task
Runnable someTask = new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello World!");
    }
};

//Thread
Thread thread = new Thread(someTask);
thread.start();

//Executor 
Executor executor = new Executor() {
    @Override
    public void execute(Runnable command) {
        Thread thread = new Thread(someTask);
        thread.start();
    }
};

Executor is just an interface which accept Runnable. execute() method can just call command.run() or working with other classes which use Runnable(e.g. Thread)

interface Executor
    execute(Runnable command)

ExecutorService interface which extends Executor and adds methods for managing - shutdown() and submit() which returns Future[About] - get(), cancel()

interface ExecutorService extends Executor 
    Future<?> submit(Runnable task)
    shutdown()
    ...

ScheduledExecutorService extends ExecutorService for planning executing tasks

interface ScheduledExecutorService extends ExecutorService
    schedule()

Executors class which is a Factory to provide ExecutorService realisations for running async tasks[About]

class Executors 
    newFixedThreadPool() returns ThreadPoolExecutor
    newCachedThreadPool() returns ThreadPoolExecutor
    newSingleThreadExecutor() returns FinalizableDelegatedExecutorService
    newWorkStealingPool() returns ForkJoinPool
    newSingleThreadScheduledExecutor() returns DelegatedScheduledExecutorService
    newScheduledThreadPool() returns ScheduledThreadPoolExecutor
    ...

Conclusion

Working with Thread is an expensive operation for CPU and memory. ThreadPoolExecutor consist of Task Queue(BlockingQueue) and Thread Pool(Set of Worker) which have better performance and API to handle async tasks

Nissy answered 10/3, 2021 at 15:12 Comment(0)
S
0

Creating a large number of threads with no restriction to the maximum threshold can cause application to run out of heap memory. Because of that creating a ThreadPool is much better solution. Using ThreadPool we can limit the number of threads can be pooled and reused.

Executors framework facilitate process of creating Thread pools in java. Executors class provide simple implementation of ExecutorService using ThreadPoolExecutor.

Source:

What is Executors Framework

Stratify answered 18/6, 2018 at 16:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.