Java Multithreading Tutorial

As we know that Multithreading in Java is a very important topic. Multithreading means doing things simultaneously, in parallel. In Java, concurrency is done with threads. Threads are units of code that can be executed at the same time. They are sometimes called lightweight processes, although, in fact, a thread is executed within a process (and every process has, at least, one thread, the main thread).

The source code examples from this up-to-date tutorial are developed using JDK 8 or later (Lambda expressions, functional interfaces etc) and well tested on our local development environment.

In this tutorial, we will learn low-level APIs that have been part of the Java platform from the very beginning. These APIs are adequate for very basic tasks. In Java Concurrency Tutorial, we will learn high-level concurrency features introduced with version 5.0 of the Java platform. Java provides multithreading support with the Thread class and an application can create multiple threads executing concurrently.

>> How to Create and Start a Thread in Java

This is the first article of this tutorial, in this article, we will learn how to create and run a thread in a Java application. Java provides two ways to create a thread programmatically. Implementing the Runnable interface and extending the Thread class.

>> Java Thread Sleep Example

In this article, we will learn how to pause the execution of a current thread. Java Thread class provides sleep method, which can be used to pause the execution of a current thread. We will use Thread sleep extensively in future posts, so it’s good to know how it works and is it accurate or not?.

>> Java Thread Join Example

Sometimes we need to wait for other threads to finish it’s execution before we can proceed. We can achieve this using Thread join, learn how it works and when we should use it.

>> Java Thread Set Name Example

In this article, we learn how to name a thread in Java. Thread class provides setName and getName Methods to name a Thread.

>> Java Thread interrupt Example

In this article, we will learn how to interrupt a running thread. An interrupt is an indication to a thread that it should stop what it is doing and do something else. 

>> Java Thread Priority Example

In this article, we will learn how to priorities threads in a Java application. Each thread has a priority. Priorities are represented by a number between 1 and 10.

>> Java Thread isAlive Example

In this article, we will learn java.lang.Thread class provides isAlive() method to test if this thread is alive or not. A thread is alive if it has been started and has not yet died.

>> ThreadGroup Class in Java

In this article, we will learn how to group threads. Java provides a convenient way to group multiple threads in a single object. Java thread group is implemented by java.lang.ThreadGroup class.

9. Thread Class in Java

In this article, we will learn important methods of Thread class with examples.

>> Runnable Interface in Java

In this article, we will learn how to use Runnable interface with examples.

>> Synchronization in Multithreading Java

In this article, we will learn how to use synchronization to avoid two types of problems arise when multiple threads try to read and write shared data concurrently - 1. Thread interference errors 2. Memory consistency errors.
We know that threads share Object’s variables but what if we want to have thread-local variables created at a class level. Java provides ThreadLocal utility class to create thread-local variables. Read more to learn about how we can create ThreadLocal variables in java program.

There is a separate Java Concurrency Tutorial for high-level concurrency features Executor framework introduced with version 5.0 of the Java platform.

Executor Framework

With an Executor framework, we only have to implement the Runnable objects and send them to the executor. The executor is responsible for their execution, instantiation, and running with necessary threads. But it goes beyond that and improves performance using a pool of threads. When you send a task to the executor, it tries to use a pooled thread for the execution of this task, to avoid continuous spawning of threads.

Another important advantage of the Executor framework is the Callable interface. It's similar to the Runnable interface, but offers two improvements, which are as follows:
1. The main method of this interface, named call(), may return a result.
2. When you send a Callable object to an executor, you get an object that implements the Future interface. You can use this object to control the status and the result of the Callable object.

Java Concurrency Tutorial

In this tutorial, we will learn following high-level concurrency features Executor framework:
  • At a low level, we can create a thread in two ways, either by implementing Runnable or by subclassing Thread and overriding the run() method.
  • At a high-level, we use Executors, which use thread pools, which in turn use worker threads.
  • One type of thread pool is the fixed thread pool, which has a fixed number of threads running. We can also use single-thread pools.
  • ExecutorService has methods to execute thread pools that either take a Runnable or Callable task. A Callable returns a result and throws a checked exception.
  • The submit() method returns a Future object that represents the result of the task (if the task is a Runnable, null is returned).
  • An executor has to be shutdown to close the pool thread with either shutdown() (gracefully) or shutdownNow() (forcefully).
  • A deadlock situation occurs when two or more threads are blocked forever, waiting for each other to acquire/release some resource.
  • Starvation happens when a thread is constantly waiting for a lock, never able to take it because other threads with higher priority are continually acquiring it.
  • A livelock is like a deadlock in the sense that two (or more) threads are blocking each other, but in a livelock, each thread tries to resolve the problem on its own (live) instead of just waiting (dead).
  • A race condition is a situation where two threads compete to access or modify the same resource at the same time in a way that causes unexpected results.
Check out top beginners to expert up-to-date Core Java Tutorial (100+ Articles)