Java Concurrency

This would require us to maintain a queue of Runnable’s and to assign and start each one when a thread becomes available.

This seems like a lot of overhead to write on our own.

It is situations like this that call for an ExecutorService.

ExecutorService can be used to write a concurrent application without the need for managing threads on our own.

Lets look at an exampleExecutorService threadPool = Executors.

newSingleThreadExecutor();Notice that we are not calling new when instantiating our ExecutorService.

That is because the class Executors has predefined factory methods that make ExecutorService creation more simple.

Here is another exampleExecutorService threadPool = Executors.

newFixedThreadPool(10);Now instead of a single threaded ExecutorService we have an ExecutorService with a pool of ten threads.

Lets see how we start a runnable using an ExecutorServicethreadPool.

submit(runnableExample);Notice that we are able to submit the Runnable class we created earlier after the ExecutorService has been created.

This is because internally the ExecutorService has its own queue that assigns tasks to available threads.

Since the overhead of assigning tasks to available threads is not our responsibility we can submit runnables to our ExecutorService in succession like belowthreadPool.

submit(runnableExample); // ExecutorService submit using Java 8 lambda expressionthreadPool.

submit(() -> { // something is happening in another thread });Notice that since Runnable is a functional interface we can use Java 8 lamda expressions to create the Runnable that our ExecutorService is submitting.

Up to this point we have been submitting a Runnable, which implements the void method run, to our ExecutorService and Thread instances.

Some of the time we will need a piece of data returned from our a task that was running in a separate thread.

ExecutorService allows us to do this using the functional interface Callable whose abstract method call has a return value.

Below is an exampleFuture<String> future = threadPool.

submit(() -> { return "the string being returned"; });Calling submit using a callable means that we have the ability to get some result when call is executed.

In order to get this result we need to use a Future since the submit method does not wait for the callable to complete before moving on to the next line of code.

The returned Future gives us access to several methods that allow us to process the data returned from our Callable.

For example we can do something like thisif (!future.

isDone()) { System.

out.

println("Not done"); } else { System.

out.

println(future.

get());}That is it.

With the info we have gathered from this overview of Runnables, Callables, Threads, and ExecutorServices we should be able to write concurrent applications and avoid blocking on any process we choose.

I hope this post was helpful and should you like to view the source code for this tutorial it is available on GitHub.

.

. More details

Leave a Reply