Skip to main content

Concurrency in Java: Creating and Starting a Thread

Multithreading in Java means that there are multiple threads of execution inside the same application executing different parts of the code at the same time.

A thread in Java is an independent path of execution that does not run 'within', but rather side-by-side with another process or thread.

When we start the JVM, there is only one process java.exe or one thread, "main".

This "main" thread or "any thread" can start another thread, so long as the OS allows it.

In Java, a thread can be created in one of the following two ways:

Implementing the Runnable Interface

In this approach, we create an instance of java.lang.Thread class, passing a java.lang.Throwable instance in its constructor and call "start()" on it.

This thread, when started, will execute code written in the overridden run() method of implementation class.

If you callĂ‚ run() directly on the "java.lang.Throwable" instance, it will still execute code written in the run() method, but it will do so in the current thread (main) instead of inside a new thread.

Similarly, if you call run() instead of start() on the "java.lang.Thread" class object, no new thread will be created.

One advantage of creating a thread by implementing the Runnable interface is that it allows the implementing class to extend some other class. (Because Java only allows for one class extendability per class).

Another advantage of this approach is that it gives you an object that can be shared amongst multiple threads.

Using anonymous "Runnable"

A thread can also be started using an anonymous "Runnable" object, as shown below.

Using lambda expression

Moreover, the syntax of this anonymous "Runnable" can be made more crisp using lambda expressions.

Extending the Thread class

In this approach, we create a Java class extending the "java.lang.Thread" class. Now to start a thread, we create an instance of this sub-class and call the start() method on it.

If a run() method is overridden in the sub-class, the code inside that is executed by the thread, otherwise a default run() method defined in the "Thread" class is executed.

If you call run() on the sub-class instance directly, it will still execute code written in the run () method, but it will do so in the current thread (main) and no new thread will be created.

We cannot run "start()" on the same instance of a "Thread" more than once. Doing so will throw an "IllegalThreadStateException" exception.

One advantage of creating a thread by extending the Thread class is that it provides some inbuilt methods like yield(), interrupt (), etc. those are not available in the Runnable interface.

Using anonymous subclass of Thread

We can also start a new thread without creating a named subclass. We can do so by creating an anonymous subclass of Thread and override run() methods as show in the example below:

Java also provides an Executor framework that can be used to create thread pools for multi-threading.


Priority of a Thread

Java schedules different threads based on the priority of a thread, also known as preemptive scheduling.

In preemptive scheduling, the higher priority task will continue to receive execution time until it enters a waiting or dead state, or until a task with a higher priority enters the scheduling queue.

Another popular scheduling method is slicing scheduling, which gives every task a fair chance of being scheduled based on time slices.

In Java, every thread has a priority, specified as a number between 1 and 10.

A new thread gets the same priority as the priority of the thread that created it.

The default priority of a thread is 5 or NORM_PRIORITY.

We can set three priorities on a thread - MIN_PRIORITY or 1, NORM_PRIORITY or 5 and MAX_PRIORITY or 10.

Thread priority is only hint to OS task scheduler. Task scheduler will try to allocate more resources to thread with highest priority, but there are no explicit guarantees.

Process vs Thread

Process

A process is an unit of execution with its own "separate memory".

Each JVM (java application) runs as a "process" and has its own memory space known as a "heap" (heap cannot be shared by multiple java applications).

Thread

A thread is an unit of execution within a process. Each java process (application or JVM instance) has at least one "thread" (main).

Every thread created inside a process shares the thread's resources (memory and files).

In addition to shared memory (heap) of the process (JVM), every thread has its own non-sharable "thread stack (memory having local variables)" and "instruction pointer (address for next instruction to execute)"

Context switching

In concurrency, a context switch is the process of storing the state (local data, program pointer) of a thread, so that it can be restored and resume execution at a later point, and then restoring a different, previously saved, state.

This allows multiple threads to share a single CPU and is an essential feature of a multithreaded application.

Context switching isn't cheap. An application should not switch between threads more than necessary.

Thread Class Methods

Thread.currentThread()

The java.lang.Thread.currentThread() method returns a reference to the currently executing thread object.

We can get useful information like "getName()", "getId()" and "getPriority()" on this current thread object.

Current thread name: CB-Thread
Current th name: main
Current th id: 1
Current thread id: 15
Current thread priority: 5
Current th priority: 5

Thread.sleep()

It is always the current thread that is put to sleep, although the thread might not sleep for the required time (or even at all).

While sleeping, the thread still owns the synchronization locks it has acquired.

When Thread is sleeping and is interrupted, the method throws an "InterruptedException" immediately and doesn't wait until the sleeping time finishes.

The major difference between "wait()" from "java.lang.Object" and "sleep()" from "java.lang.Thread" is that wait() method releases the acquired monitor when the thread is waiting, while Thread.sleep() method keeps the lock or monitor even if the thread is waiting.

Current th: main
Current th: main
Current thread: CB-Thread
Current th: main
Current thread: CB-Thread

Thread.setUncaughtExceptionHandler()

The java.lang.Thread.setUncaughtExceptionHandler() sets the handler to be invoked when this thread abruptly terminates due to an uncaught exception.

Current thread: Th Thread
A critical exception happened in thread: Th Thread

Comments

Popular posts from this blog

Deploying Spring Boot microservices on Kubernetes Cluster

This article guides you through the deployment of two Spring Boot microservices, namely "order-service" and "inventory-service," on Kubernetes using "MiniKube" . We will establish communication between them, with "order-service" making calls to an endpoint in "inventory-service." Additionally, we will configure "order-service" to be accessible from the local machine's browser . 1) Create Spring Boot microservices The Spring Boot microservices, "order-service" and "inventory-service," have been developed and can be found in this GitHub repository. If you are interested in learning more about creating Spring Boot REST microservices, please refer to this or this (Reactive) link. 2) Build Docker Images The Docker images for both "order-service" and "inventory-service" have already been generated and deployed on DockerHub, as shown below. codeburps/order-service cod...

Circuit Breaker Pattern with Resilience4J in a Spring Boot Application

Read Also: Spring Cloud Circuit Breaker + Resilience4j Resilience4j is a lightweight fault tolerance library that draws inspiration from Netflix Hystrix but is specifically crafted for functional programming. The library offers higher-order functions, known as decorators , designed to augment any functional interface, lambda expression, or method reference with features such as Circuit Breaker, Rate Limiter, Retry, or Bulkhead . These functionalities can be seamlessly integrated within a project, class, or even applied to a single method. It's possible to layer multiple decorators on any functional interface, lambda expression, or method reference, allowing for versatile and customizable fault tolerance. While numerous annotation-based implementations exist online, this article focuses solely on the reactive approach using router predicates and router functions . How Circuit Breaker Pattern works? In general, a circuit breaker functions as an automatic electrical s...

How to create a basic Spring 6 project using Maven

Below is a step-by-step guide to creating a basic Spring project using Maven. 1) Create a Maven Project Use the following Maven command to create a new Maven project. mvn archetype:generate -DgroupId=com.tb -DartifactId=spring-demo -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false 2) Import in IntelliJ IDEA If you haven't already, open IntelliJ IDEA on your system. Go to "File" > "New" > "Project from Existing Sources..." . In the file dialog, navigate to the directory where your Maven project is located. Select the pom.xml file within the project directory and click "Open." 3) Update pom.xml In total, the application requires the below-mentioned dependencies: 4) Create Spring Configuration Create a Java configuration class that uses annotations to define your Spring beans and their dependencies. This class should be annotated with @Configuration . 5) Create the Main Application C...