What are threads in Java?

Overview

A thread is sequence or flow of execution in a Java program. Threads are known as a lightweight process since they share the same data and process address space.

Thread priority

Every thread has a priority that determines its preference for execution. Threads can have priorities ranging from [1…10], including the following values:

java.lang.Thread.MIN_PRIORITY = 1

java.lang.Thread.NORM_PRIORITY = 5

java.lang.Thread.MAX_PRIORITY = 10

Scheduling of threads

Threads are scheduled by Java runtime using the fixed-priority scheduling algorithm.

Threads with a higher priority generally (but this is not guaranteed) execute before threads with lower priority.

However, JVM may decide to execute a lower priority thread before a higher priority thread to prevent starvation. A thread may, at any time, also decide to give up its right to execute by calling the yield method.

Threads can only yield the CPU to other threads that have the same priority – if a thread attempts to yield to a lower priority thread, the request is ignored.

Types of threads

There are two kinds of threads, a user thread and a daemon thread.

User Threads – User threads are normal threads and are generally used to run our program code.

Daemon Threads – Daemon threads are also known as service provider threads – they are generally used to execute some system code. JVM terminates daemon threads if no user threads are running. Therefore, daemon threads should not be used to perform our program logic.

The Life cycle of a thread is explained in the illustration below.

Lifecycle of a Thread

Threads implementation:

  1. Using thread class
  2. Using a runnable interface

These two implementations can be viewed here.

We can further simplify the runnable interface by:

Using the Anonymous class implementation of Runnable

The runnable interface example can be further simplified by using the anonymous implementation of the Runnable interface.

Execute the code below to understand this approach:

public class Main {
public static void main(String[] args) {
// creating and starting a new thread using annonymous class
Runnable runnable = new Runnable () {
public void run() {
// actions to be performed within thread
// ... 
System.out.println("Inside MyThread");
}
};
Thread t = new Thread(runnable);
t.start();
System.out.println("Inside main method");
// changes the thread priority
t.setPriority(Thread.MAX_PRIORITY);
//t.setPriority(Thread.MIN_PRIORITY);
try {
// causes the thread to temprorarily stop execution
t.sleep(1000); // 1000 milliseconds
} catch (InterruptedException e) {
e.getMessage();
}
}
}

Using the Lambda Expression implementation of Runnable

If you are using Java 8 or later, using the Runnable Implementation of thread can be even further simplified with the lambda expressions for Runnable interface.

Take a look at, and execute, the example below:

public class Main {
public static void main(String[] args) {
// creating and starting a new thread using annonymous class
Runnable runnable = () -> {
// actions to be performed within thread
// ... 
System.out.println("Inside MyThread");
};
Thread t = new Thread(runnable);
t.start();
System.out.println("Inside main method");
// changes the thread priority
t.setPriority(Thread.MAX_PRIORITY);
//t.setPriority(Thread.MIN_PRIORITY);
try {
// causes the thread to temprorarily stop execution
t.sleep(1000); // 1000 milliseconds
} catch (InterruptedException e) {
e.getMessage();
}
}
}

This is the most preferred approach due to the readability and conciseness of the code.

Conclusion

The use of the runnable interface is preferred as the first approachRequires the extension of the thread class limits the MyThread class to further extend another class due to the lack of multiple inheritance support in Java.

Free Resources