{{announcement.body}}
{{announcement.title}}

Executor and Execution Context Objects in Scala

DZone 's Guide to

Executor and Execution Context Objects in Scala

Learn more about Executor and Execution Context objects in Scala.

· Java Zone ·
Free Resource

Executor Context Objects

Learn more about Executor and Execution Context objects in Scala.

Thread and Runnable have been around for a long time as two of the first concurrent execution approaches in Scala. Creating a new Thread takes less computational time compared to creating a new JVM process. We cannot afford to create a fresh Thread for each of these tasks, because if an application performs a large number of small concurrent tasks, then it requires high throughput.

You may also like: A Scalable Java Thread Pool Executor

In this post, we are going to discuss the Executor and Execution Context objects with specific code examples. Let's get started.

java7-concurrency-11-638

Thread Pools

Starting a Thread required us to allocate a memory region for its call stack and context switch from one Thread to another. But this consumes much more time than work in the concurrent task. For this reason, most concurrency frameworks have facilities that maintain a set of Threads in a waiting state and start running when concurrently executable work tasks become available. Generally, we call such facilities Thread pools.

To allow programmers to encapsulate the decision of how to run concurrently executable work tasks, the JDK comes with an abstraction called Executor. The Executor is an interface, and in this, a single execute method is defined. This method takes a runnable object and calls its run method.

ForkJoinPool

ForkJoinPool is an Executor introduced in JDK 7.  Its threads are daemons by default, which means there is no need to shut it down explicitly at the end of the program. Scala programmers can use it in JDK 6 by importing scala.concurrent.forkjoin package. Let’s see the implementation and submit tasks that can be asynchronously executed. 

In this code, first, we import the package and instantiate ForkJoinPool class and assign it to the executor. Now, this executor sent the task in the form of a runnable object that prints to the standard output. Finally, we use Thread.sleep to prevent the daemon threads in the ForkJoinPool instance from being terminated.

ExecutorService

It is the subtype of Executor interface which also implemented by the ForkJoinPool class. ExecutorService extends Executor which defines convenience methods. In this, I will talk about the shutdown method, this method makes sure that the Executor object terminates by all executing all the submitted tasks and then stopping all the worker threads. When your program no longer needs the ExecutorService object you created, you should ensure that the shutdown method is called.

In the above example, we used the sleep method. To prevent this, we can use the awaitTermination method. This method specifies the maximum amount of time to wait for their completion. Let’s see the example (this code is a continuation of the above code).

import java.util.concurrent.TimeUnit
executor.shutdown()
executor.awaitTermination(60, TimeUnit.SECONDS)


Execution Context

If you are a Scala programmer, then you know that the scala.concurrent package defines the ExecutionContext trait and offers similar functionality to that of the Executor objects. Many Scala methods take ExecutionContext objects as implicit parameters. It implements the abstract execute method, which perfectly corresponds to the execute method on the Executor interface and the reportFailure method. The ExecutorContext companion object contains the default execution called global, which internally uses a ForkJoinPool instance. With this, we can pass the parameter or import the package. 

Let’s look at an example:

object ExecutionContextGlobal extends App {
val ectx = ExecutionContext.global
ectx.execute(new Runnable {
def run() = log("Running on the execution context.")
})
Thread.sleep(500)
}


In this example, we instance the global to ectx and then send the task in the form of a Runnable object.

By importing the package:

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
val fut = Future { Thread.sleep(10000); 21 + 21 }


In this example, we imported global to globally, which means we don’t need to instance global again and again.

Thank you for reading to the end. If you liked this post, please do show your appreciation by giving it a like and sharing this blog. And don't forget to share your feedback in the comments.

Further Reading

A Scalable Java Thread Pool Executor

Java Multi-Threading With the ExecutorService

Topics:
scala ,java ,threading ,concurency ,data ,multithread execution ,context handling ,execution context ,java interview questions ,fork and join

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}