Java Concurrency API

S. Ünal
9 min readDec 17, 2021
source:https://store.hp.com/app/assets/images/uploads/prod/what-is-a-cpu-how-to-monitor-usage-hero1567114040788405.jpg

Java supports multithreading since Java 1.1 with various classes, interfaces as Thread, Process, Runnable etc. Although they were no noticeable changes with the next versions, the biggest change came with Java 1.5.

Java 1.5 brought new changes to the multithreading within java.util.concurrent such as Executor, ExecutorService, Future, Semaphore etc. Thanks to the development of java.util.concurrent, many of the struggles with multi threading became easier to handle.

CONTENTS

1. A Brief Introduction to Multithreading and Concurrency
____1.1. Threads
____1.2. Concurrency
____1.3. Runnable Functional Interface
2. Java Concurrency API
(java.util.concurrent)
____2.1. Executor
____2.2. ExecutorService
____2.3. ScheduledExecutorService
____2.4. Thread Pools
____2.5. Future
____2.6. Callable Functional Interface
____2.7. CountDownLatch
____2.8. CyclicBarrier
____2.9. Semaphore
____2.10. ThreadFactory
____2.11. BlockingQueue
____2.12. DelayQueue
____2.13. Lock
____2.14. Atomic Classes
3. Conclusion
4. References

1. A Brief Introduction to Multithreading and Concurrency
Multithreading is an application or a group of applications to execute multiple tasks simultaneously. Since early stages, java supports multithread programming by using Thread class. An example project to a single threaded program can be as below, in which the code execution flow from top to bottom on a single thread.

And the output is:

Output of single threaded program

____1.1 Threads
A thread means the smallest unit of execution which can be scheduled by the operating system.

A group of associated threads that execute in the same and shared environment is called a process. Single threaded process means the process that contains one thread only, multi threaded process on the other hand, means the process that contains one or more threads.

Single unit of work which is executed by thread is called as task. Even though a thread can complete multiple tasks, it can execute only one task a time.

Process model

____1.2 Concurrency
Execution of multiple processes and threads simultaneously is called as concurrency. Concurrency exists in modern programming such as multiple computers in a network, multiple applications running on one computer or multiple processors in a computer(i.e. multiple processor cores on one chip).

Concurrency is very important in modern programming since;

  • Websites must execute processes of multiple users
  • Some mobile apps need to do some of the processing on servers (“in the cloud”).
  • Graphical user interfaces generally require processes on the background that does not interrupt the user. For example, an IDE like Eclipse compiles the Java code while the user still editing it.

As mentioned previously, multithreading can be achieved by extending Thread class.

System.out.println("END"); is at the end of main method, however it executed wihtin main thread and in the output it can be seen that the counters of each animal executes on different Threads than the main thread.

Output of multi threaded program(extending Thread class)

However extending Thread class to achieve multi threading is generally not preferred. The reasons will be explained in the next section.

____1.3 Runnable Functional Interface
The functional interface Runnable is commonly used to define the job that will be executed by a thread. It has one method only which is :

public abstract void run();

Lets change the previous example with Runnable interface:

And also the main class should be adjusted:

As a result, the output is:

Output of multi threaded program(implementing Runnable interface)

As mentioned in the previous section, implementing Runnable is much more preferred over extending Thread class, since:

  • In Java it is possible to extend one class only, therefore extending Thread class prevents extending other classes
  • When Thread class is extended, each of thread creates unique object and associate with it. When Runnable interface is implemented, it shares the same object to multiple threads.

2. Java Concurrency API(java.util.concurrent)
Java 5 brought new changes as Java Concurrency API to handle multi thread programming better.

____2.1. Executor
Executor interface is used to represent an object that executes the defined task. Executor interface has no assumption about how the task is executed. It has one method only as execute, which executes the provided task at some time in the future.

And the output is:

Output of multi threaded program(using Executor)

____2.2 ExecutorService
ExecutorService is an extended interface of Executor. It goes one step beyond and provides several utility methods when compared with Executor interface. Such as shutting down thread pool or getting the result of a task.

The interface has several methods, these are the most used among them:

  • execute: comes from Executor interface. It does the same thing.
  • submit: submits a runnable task or value-returning task(Callable interface, which will be mentioned later on) to be executed and returns a Future Object(result of a task, which will also be mentioned later on).
  • shutdown: triggers a shutdown, and allows the previously provided tasks to be executed and rejects any new task.
  • shutdownNow: triggers shutdown to terminate all the previously provided but not finished tasks. It returns the list of terminated tasks.
Output of multi threaded program(using ExecutorService)

Although submit and execute seems similar, there is one important difference, submit does the exact thing execute does, however submit returns a Future Object which can be useful to track the result. It is preferred to use submit instead of execute even if the Future Object is not used since execute does not support Callable.

____2.3 ScheduledExecutorService
This interface is similar to ExecutorService, but it can execute the tasks periodically and/or with a delay. Both Runnable and Callable can be used to define the tasks.

Lets change the previous code example to define some delays with scheduled method.

On the output it can be seen that, the parrot task starts to execute last and cat task starts to execute in the second order as they have more delays then parrot task.

Output of multi threaded program(using ScheduledExecutorService)

The is two other methods to execute the tasks which are scheduleAtFixedRate and scheduleWithFixedDelay. Lets use scheduleAtFixedRate to run the cat task periodically. In given code below, cat task will start 0 seconds of delay and will repeat to execute the task each 2 seconds. Then awaitTermination ensures that the task will not execute infinitely but 5 seconds.

On the output it can be seen that, cat task is executed 3times which are at t=0 second, t=2 second and t=4 second, at t=5second moment, the task is terminated.

Output of multi threaded program(using ScheduledExecutorService — scheduleAtFixedRate )

____2.4 Thread Pools
It can be noticed in the outputs of the section 1.2 and 1.3 that the created threads run concurrently with main thread but they also run concurrently with each other. However this was changed when the section with Java Concurrency API classes comes . The reason is on the first examples a new Thread is created for each task in the first examples, however, on Java Concurrency API examples, each task run on the same thread. So each task do not work concurrent with each other but with the main thread.

The utility class Executors has various factory methods to create a pool of Threads along with the method that creates one Thread only which were used on Java Concurrency API code examples previously. The term “thread pool” here means a set of pre-instantiated reusable threads which can execute a group of arbitrary task.

A pool of threads can be created with:

  • newCachedThreadPool()
  • newFixedThreadPool(int nThreads)
  • newScheduledThreadPool(int nThreads)

Lets adjust the main class to use a pool of threads instead of one thread only.

Now each task runs concurrent with each other also.

Output of multi threaded program(using thread pools)

____2.5. Future
Future object represents the asynchronous execution result. It has various methods such as:

  • get: waits if the task is not complete then retrieves the result
  • cancel:cancels the execution of the task. It fails if the task is completed or canceled already.
  • isDone: returns true if the task is completed
  • isCanceled: returns true if the task was canceled before it completes

____2.6. Callable Functional Interface
Callable is a functional interface with the method call(). Unlike Runnable interface, it has a generic return value. The result comes wrapped with Future.

Lets create a class that extends Callable:

With these adjustments, each task returns the LocalDateTime value of the moment they finished their execution.

Output of multi threaded program(using Callable)

____2.7. CountDownLatch
CountDownLatch is an Utility class to block a thread or threads until the defined counter within is reached to zero. By setting a proper value of integer for the counter and by decrementing the counter each time a specific set of tasks is complete, it can be achieved the desired task to wait that specific set of tasks.

Lets define another Runnable class to use CountDownLatch:

Lets also define a CountDownLatch with integer 1 and use await method of CountDownLatch to make the main thread waits until parrot is complete. Then the main thread and the thread for cat task and duck task will be executed. The order of execution will be determined by OS Thread scheduler.

The main method should also be adjusted:

Output of multi threaded program(using CountDownLatch to achieve block)

____2.8. CyclicBarrier
CylicBarrier is a similar class as CountDownLatch. It is used make a set of threads wait each other before running further. When all of these set of threads call await() method of CylicBarrier, then they proceed further.

CyclicBarrier can be thought as the friends having a dinner. Each friend arrives at the restourant and waits the other. When all the friends arrive(when they all do “waiting”), they start to order dinner.

Unlike CountDownLatch which cannot be used again after it reaches zero, CyclicBarrier can be used again with reset() method.

____2.9. Semaphore
Semaphore blocks thread-level access to some part of physical or logical resource. A Semaphore has a group of permits, when a thread tries to go in the critical section, it requires to check the semaphore whether the permit is available. If the permit is available(checked by tryAcquire()) , the thread can access to the critical section and permit counter decreases. If the permit is not available, then the access is blocked. When a thread is done with critical section, it should call release() method, which increases the permit counter back.

____2.10. ThreadFactory
This interface acts as a thread pool which can create a new thread on demand. Implementing this interface gives to the writer the control over the creation of Threads.

One example reason to use a ThreadFactory would be that logging the creation of threads or logging uncaught exceptions that is thrown during task execution.

To implement this, first a class that implements ThreadFactory should be created.

Each of Executors factory methods that are mentioned in this article has another overloaded variants that take ThreadFactory parameter also.

____2.11. BlockingQueue
Producer-consumer pattern is a very common integration pattern that is used in multi thread programming. BlockingQueue is a data structure that can be used in such scenarios.

____2.12. DelayQueue
DelayQueue is an infinite-size blocking queue of elements. The only case that an element of a blocking queue can be pulled is its expiration time(a delay defined by the developer) is complete.

____2.13. Lock
Lock can block other threads access to some part of the code, apart the access of the current thread.

____2.14. Atomic Classes
Concurrency can cause problems when involves in a shared mutable state. Although this problem can be solved by using volatile and synchronized keywords properly. However blocking a thread then allowing it to resume mostly reduces performance.

Java Concurrency API brought also data types which can read and set the data atomic. Some examples are AtomicInteger, AtomicBoolean, AtomicReference etc.

Lets try this with the example below.

And the output is:

Comparison of normal int and AtomicInteger

--

--