Skip to main content
Java

Java Threads

4 mins

A multi-track railway with several trains running on different tracks, representing the multiple paths of execution in a multi-threaded program, with each train symbolizing a thread

What is a Thread #

Typically when you start programming, your would write a program where it would have a number of statements that would be executed one after the other. This is called a single-threaded program. However, in a multi-threaded program, you can have multiple threads executing at the same time.

In multi-threaded programs, you would multiple paths of execution, all running at the same time. Each path of execution is called a thread. One thread would be the main thread, and the other threads would be the child threads running concurrently with the main thread.

Threads can make your program more performant and responsive.

For example, if you are obtining data from multiple sources, you can have a thread for each source, and all the threads would be running concurrently. This improves the performance of the program, as the program can obtain data from multiple sources at the same time.

Similarly, if you are writing a game, you can have a thread for the game logic, a thread for the graphics, and a thread for the sound, making the game run more smoothly and responsively.

Multithreading Benefits #

The benefits of multithreading include:

  • Concurrency: Allows multiple parts of a program to run concurrently.
  • Resource Sharing: Threads share the same memory and resources of the process they belong to.
  • Responsiveness: Multithreaded applications can remain responsive to input even when part of the program is busy.
  • Performance: Can lead to better performance on multi-core or multi-processor systems.

Creating Threads #

In Java, you can create a thread by

  1. Extending the Thread class and overriding the run method.
  2. Implementing the Runnable interface and providing an implementation for the run method.

Extending the Thread class #

To create a thread by extending the Thread class, you would create a new class that extends the Thread class and override the run method. The run method is the entry point for the thread. It is where the code for the thread is written.

Here is an example of a thread that extends the Thread class:

class MyThread extends Thread {
    public void run() {
        System.out.println("MyThread is running");
    }
}

public class Main {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
    }
}

Implementing the Runnable interface #

To create a thread by implementing the Runnable interface, you would create a new class that implements the Runnable interface and provide an implementation for the run method. Then you would create a new instance of the class and pass it to a new instance of the Thread class.

Here is an example of a thread that implements the Runnable interface:


class MyRunnable implements Runnable {
    public void run() {
        System.out.println("MyRunnable is running");
    }
}   

public class Main {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);
        thread.start();
    }
}

In both examples, the start method is called on the thread object to start the thread. The start method is a method of the Thread class that starts the thread and calls the run method.

Callable and Future #

Neither of the above methods of creating threads allows the thread to return a value or throw an exception. To create a thread that can return a value or throw an exception, you can use the Callable and Future interfaces.

The Callable interface is similar to the Runnable interface, but it can return a value or throw an exception. The Future interface is used to retrieve the result of the Callable interface.

Here is an example of a thread that implements the Callable interface:

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

class MyCallable implements Callable<String> {
    public String call() {
        return "MyCallable is running";
    }
}

public class Main {
    public static void main(String[] args) {
        MyCallable myCallable = new MyCallable();
        FutureTask<String> futureTask = new FutureTask<>(myCallable);
        Thread thread = new Thread(futureTask);
        thread.start();
    }
}

In the example above, the call method of the MyCallable class returns a String. The FutureTask class is used to retrieve the result of the MyCallable class.