Creating and Starting a Thread in Java Tutorial

In this section, we will learn how to create and run a thread in Java.

Note: we’re assuming you’re already familiar with the idea of multithreading and concurrency in Java.

How to Create a Thread in Java?

In order to create a thread in a Java program, there are multiple steps that need to be taken:

  • We need to create an instance of a class called `Thread`.
  • The created instance has a method called `start()`. The moment we call this method, that’s where the thread will get the required resources from the JVM and then it will move into the runnable state (meaning the OS puts the thread on the queue of threads that are waiting for the CPU’s time to execute their instructions).
  • We need to pass a set of instructions to a thread to run. This is done using a method called `run()`. There are multiple ways to access this method and insert the target instructions to it, which we will explain them in just a second.
  • At the end, after a thread ran the instructions of the target `run()` method, its work is done and the thread will be gone then. (Note that you can’t call the start() method of a thread two times in a row! This is because a thread is a path of execution and so after the CPU went this path and ran every instruction of that thread, the OS won’t schedule that thread for another execution of its instructions!

Thread class

As mentioned before, you can create a thread in a Java program by creating an instance of the Thread class.

This class has multiple constructors but some of the most important of them are:

Thread ();

Thread (String name);

Thread (Runnable runnable);

Thread (Runnable runnable, String name);

Using the first constructor will give us an instance of this class that has already its `run()` method which doesn’t have any instructions in its body. This means, if we run the target thread using a call to the `start()` method, the target thread will immediately go dead because there’re no instructions to run in the body of the `run()` method.

Using the second form of the constructor allows us to set a name for the newly created thread as well. This name can help us to debug a program at later time (Especially if there are multiple threads in a program, setting names for these threads can help us tremendously).

Now, the second form of the constructor is where things get interesting! This constructor has a parameter of type `Runnable` which is a functional interface. This functional interface has a method called `run()`, sounds familiar? You see, the Thread class already implemented this interface and overrode the `run()` method in its body! So, if you create an object using the default constructor of this class, you’ll get the `run()` method of the Thread class itself, which is an empty one! Now, by this third form of constructor, the Thread class allowed us to implement the `Runnable` interface and create an instance from it and finally pass that as the argument of this constructor. At this time, the new thread instead of using the run() method of the `Thread` class, it will use the one that we’ve passed as the argument of the constructor.

This is the opportunity that we can take advantage of and place any instructions in the target run() method of the implemented Runnable interface and pass that as the argument of the target thread object. As a result, the new thread will run our instructions.

Alright, things got a bit confusing! So let’s go and run an example to see how these pieces are put together and then we will continue our discussions related to threads from there.

Example: Creating threads via Thread class

public class Test {

    public static void main(String[] args){
        
        Runnable runnable = ()->{
          for (int i = 0 ; i<5; i++){
              System.out.println(Thread.currentThread().getName());
          }
        };
        Thread t1 = new Thread(runnable, "Thread One");
        Thread t2 = new Thread(runnable, "Thread Two");
        Thread t3 = new Thread(runnable, "Thread Three");
        t1.start();
        t2.start();
        t3.start();
    }

}

Output:

Thread One

Thread One

Thread Three

Thread Two

Thread Two

Thread Two

Thread Two

Thread Two

Thread Three

Thread Three

Thread Three

Thread Three

Thread One

Thread One

Thread One

How does creating thread via Thread class works?

In the last example, we’ve created an instance of the `Runnable` interface and passed that as the arguments of three instances of the `Thread` class.

Within the body of the overridden `run()` method, we have a for-loop that runs 5 times and sends the name of the thread that running it to the output stream, per each iteration.

So here, after calling the `start()` method on each thread, they started running (or at least start to compete with each other to get the CPU’s time). Note that at this time, each thread gets its own copy of the `run()` method! Basically, since each thread has its own stack, they take a copy of the `run()` method and bring that into their stack and each thread starts to run the instructions in this method independently from the other threads.

Also, as the output shows, the order of execution of thread is by no means sequential! This means, at one point, you might see that the first thread is taking the CPU’s time, but immediately comes the last thread and then may or may not the second third, etc. (The order of executions of threads is something that the OS decides upon. So we can’t predict the order of execution for threads).

Note: there are methods that we can use to put restrictions on the order of threads’ execution. These methods are covered in later sections.

Java Runnable run() method

Just to remind you again, it is the `run()` method that a newly created thread will try to run its instructions. This method belongs to the `Runnable` interface, which is a functional one. By default, the Thread class has an empty version of this method (Because this class implemented the Runnable interface) and if we create an instance of this class using the default constructor, nothing will happen (again, because the run() method of the Thread class is empty). But, we can implement the Runnable interface and override the run() method and pass an instance of this interface as the constructor of the `Thread` class to make the target thread to use the run() method that we’ve provided.

Java Thread Class and Inheritance: overriding the run() method

Another way to override this `run()` method is by making a class to extend to the Thread class and override this method in that child class. Now, if we create an instance using the child class, the new thread will use the `run()` method of the child class and run the instructions that are defined there.

Example: inheriting from the Thread class

Create a class with the name Child and a body like this (Make sure the class is extending to the Thread class):

public class Child extends Thread{

    @Override
    public void run(){
        System.out.println("This message is coming from the run method of the Child class");
        System.out.println(Thread.currentThread().getName());
    }
}

Now, in your main method, write the code below:

public static void main(String[] args) {
    
    Thread t1 = new Child();
    t1.start();
}

Output:

This message is coming from the run method of the Child class

Thread-1

As you can see, this time we’ve made the Child class to inherit from the Thread class and so inside the body of the `Child` class we got the opportunity to override the `run()` method and defined the instructions that we wanted to be executed by the target thread.

After that, we’ve used the `Child` class and created a thread object as a result.

Java Thread start() Method

Just to remind you one last time, calling the `start()` method is when the target threads get the required resources (like the stack area) and that’s the time when the threads start running.

So, make sure to call this method when you want to start the work of a new thread.

Leave a Reply