User Professor Hans Noodles
Professor Hans Noodles
Level 41

Multithreading: What the methods of the Thread class do

Published in the Java Developer group
Hi! Today we'll continue to talk about multithreading. Let's examine the Thread class and what a few of its methods do. When we studied class methods previously, we usually just wrote this: <method name> -> <what the method does>. Multithreading: What the methods of the Thread class do - 1This won't work with Thread's methods :) They have more complex logic that you won't be able to figure out without a few examples.

The Thread.start() method

Let's start by repeating ourselves. As you probably recall, you can create a thread by making your class inherit the Thread class and overriding the run() method. But it won't start itself, of course. To do this, we call our object's start() method. Multithreading: What the methods of the Thread class do - 2Let's recall the example from the previous lesson:

public class MyFirstThread extends Thread {

   @Override
   public void run() {
       System.out.println("Thread executed: " + getName());
   }
}


public class Main {

   public static void main(String[] args) {

       for (int i = 0; i < 10; i++) {
           MyFirstThread thread = new MyFirstThread();
           thread.start();
       }
   }
}
Note: To start a thread, you must call the special start() method rather than the run() method! This is an easy error to make, especially when you first start studying multithreading. In our example, if you call the run() method 10 times instead of start(), you would get this:

public class Main {

   public static void main(String[] args) {

       for (int i = 0; i < 10; i++) {
           MyFirstThread thread = new MyFirstThread();
           thread.run();
       }
   }
}
Look at the results of our program: Thread executed: Thread-0 Thread executed: Thread-1 Thread executed: Thread-2 Thread executed: Thread-3 Thread executed: Thread-4 Thread executed: Thread-5 Thread executed: Thread-6 Thread executed: Thread-7 Thread executed: Thread-8 Thread executed: Thread-9 Look at the order of the output: Everything is happening in perfect order. Weird, huh? We're not used to this, because we already know that the order in which threads are started and executed is determined by a superior intellect inside our operating system: the thread scheduler. Maybe we just got lucky? Of course, this isn't about luck. You can verify this by running the program a couple more times. The issue is that call the run() method directly has nothing to do with multithreading. In this case, the program will be executed on the main thread, the same thread that executes the main() method. It simply successively print 10 lines on the console and that's it. 10 threads haven't been started. So, remember this in the future and constantly check yourself. If you want the run() method to be called, call start(). Let's go further.

The Thread.sleep() method

To suspend execution of the current thread for a while, we use the sleep() method. Multithreading: What the methods of the Thread class do - 3The sleep() method takes a number of milliseconds as an argument, which indicates the amount of time to put the thread to sleep.

public class Main {

   public static void main(String[] args) throws InterruptedException {

       long start = System.currentTimeMillis();

       Thread.sleep(3000);

       System.out.println(" - How long did I sleep? \n - " + ((System.currentTimeMillis()-start)) / 1000 + " seconds");

   }
}
Console output: - How long did I sleep? - 3 seconds Note: the sleep() method is static: it sleeps the current thread. That is, the one currently being executed. Here's another important point: a sleeping thread can be interrupted. In this case, the program throws an InterruptedException. We'll consider an example below. By the way, what happens after the thread wakes up? Will it continue to be executed right from where it left off? No. After a thread wakes up, i.e. the time passed as an argument to Thread.sleep() has passed, it transitions into runnable state. But, this doesn't mean that the thread scheduler will run it. It may quite possibly give preference to some other non-sleeping thread and allow our freshly-awakened thread to continue its work a little later. Be sure to remember this: waking up doesn't mean continuing work immediately!

The Thread.join() method

Multithreading: What the methods of the Thread class do - 4The join() method suspends execution of the current thread until another thread finishes. If we have 2 threads, t1 and t2, and we write

t1.join()
then t2 won't start until t1 has finished its work. The join() method can be used to guarantee the execution order of threads. Let's consider how the join() method works in the following example:

public class ThreadExample extends Thread {

   @Override
   public void run() {

       System.out.println("Thread started: " + getName());

       try {
           Thread.sleep(5000);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
       System.out.println("Thread " + getName() + " is finished.");
   }
}


public class Main {

   public static void main(String[] args) throws InterruptedException {

       ThreadExample t1 = new ThreadExample();
       ThreadExample t2 = new ThreadExample();

       t1.start();


 /* The second thread (t2) will start running only after the first thread (t1)
       is finished (or an exception is thrown) */
       try {
           t1.join();
       } catch (InterruptedException e) {
           e.printStackTrace();
       }

       t2.start();

       // The main thread will continue running only after t1 and t2 have finished
       try {
           t1.join();
           t2.join();
       } catch (InterruptedException e) {
           e.printStackTrace();
       }

       System.out.println("All threads have finished. The program is finished.");

   }
}
We created a simple ThreadExample class. Its task is to display a message that the thread has started, fall asleep for 5 seconds, and then finally report that the work is complete. Piece of cake. The main logic is in the Main class. Look at the comments: we use the join() method to successfully manage the threads' execution order. If you remember how we started this topic, execution order is handled by the thread scheduler. It runs threads at its own discretion: each time in a different way. Here we are using the method to guarantee that the t1 thread will first be started and executed first, then the t2 thread, and only after that will the program's main thread continue. Moving on. In real programs, you'll often find situations when you will need to interrupt the execution of a thread. For example, our thread is running, but it's waiting for a certain event or condition. If it occurs, then the thread stops. It would probably make sense if there was some sort of stop() method. But it's not so simple. Once upon a time, Java actually did have a Thread.stop() method and allowed a thread to be interrupted. But it was later removed from the Java library. You can find it in the Oracle documentation and see that it is marked as deprecated. Why? Because it just stopped the thread without doing anything else. For example, the thread might be working with data and changing something. Then in the middle of its work it was abruptly and unceremoniously cut off by the stop() method. Without a proper shutdown, nor the release of resources, not even error handling — there was none of this. To exaggerate slightly, the stop() method simply destroyed everything in its way. It was like pulling the power cord from the outlet to turn off the computer. Yeah, you can get the desired result. But everybody knows that after a couple of weeks the computer won't be thanking you for treating it that way. That's why the logic for interrupting threads changed in Java and now uses a special interrupt() method.

The Thread.interrupt() method

What happens if the interrupt() method is called on a thread? There are 2 possibilities:
  1. If the object was in the waiting state, for example, due to the join or sleep methods, then the wait will be interrupted and the program will throw an InterruptedException.
  2. If the thread was in a functioning state, then the boolean interrupted flag will be set on the object.
But we have to check the value of this flag on the object and correctly complete the work on our own! That's why the Thread class has the boolean isInterrupted() method. Let's return to the clock example that was in a lesson in the basic course. For convenience, we've simplified it slightly:

public class Clock extends Thread {

   public static void main(String[] args) throws InterruptedException {
       Clock clock = new Clock();
       clock.start();

       Thread.sleep(10000);
       clock.interrupt();
   }

   public void run() {
       Thread current = Thread.currentThread();

       while (!current.isInterrupted())
       {
           try {
               Thread.sleep(1000);
           } catch (InterruptedException e) {
               System.out.println("The thread was interrupted");
               break;
           }
           System.out.println("Tick");
       }
   }
}
In this case, the clock is started and starts ticking every second. In the 10th second, we interrupt the clock's thread. As you already know, if the thread that we're trying to interrupt is in one of the waiting states, the result is an InterruptedException. This is a checked exception, so we can be easily catch it and execute our logic to finish the program. And that's just what we did. Here's our result: Tick Tick Tick Tcik Tick Tick Tick Tick Tick The thread was interrupted This concludes our introduction to the Thread class's most important methods. Good luck!
Comments (15)
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION
DarthGizka Level 24, Wittenberg, Germany
5 June 2021
Try as I might, I cannot see how the code in the last example managed to switch the letters 'i' and 'c' in just one of the outputs ... Java must be a very subtle language. 🥳 (Please delete should the aforementioned phenomenon cease to exist.)
Gellert Varga Level 19, Szekesfehervar, Hungary
10 April 2021
I think it's very important to note: throwing of an InterruptedException causes also an other effect: it resets the interrupted flag to false. - So, without using the "break" command, this would be an infinite loop, because: catch block catches the Exception, we step out from the catch block with the interrupted flag set to false value, so the condition in the "while" loop will be true again (but now forever). - Instead of break command you can also use for example: current.interrupt(); This command sets the interrupted flag to true again. (So the condition in the while loop will be false = loop-breaking.) - Or, instead all of this we can use an other construction:

try {
    while (!current.isInterrupted()) {
        Thread.sleep(1000);
        System.out.println("Tick");
    }
} 
catch (InterruptedException ie) {
    System.out.println("It was interrupted");
}
In this case throwing of an Exception means: it will step out from the while loop definitively, it goes to the catch-block.
Anatoly Level 17
9 March 2021
TypO
Szymon Level 34, Warsaw, Poland
22 November 2020
Hey what would happen if we interrupt our thread not during his "sleeping time" but during the little time gap while it is processing commands? E.g. just after the loop condition was checked (and it was true at the time) and just before the sleep() method was called. Will it proceed (sleep for 1s) until the loop condition is checked again?
Switch/Cypher Level 25, Bexleyheath, United Kingdom
29 September 2020
In the last example why do you need to write:

Thread current = Thread.currentThread();
Why can't you just write:

while(!Thread.currentThread.isInterrupted())
HaeWon Chung Level 17, Boston, United States
14 June 2020
2 questions 1. The code in the join() session, why do you have to use t1.join() twice? Is it because t1 thread is still running due to InterruptedException error and want to make sure to finish t1 before main thread starts? 2. In interrupt() session, what happens if I change

while (!current.isInterrupted())
to

while(true)
I got the exact same result when I change as above. clock thread will be interrupted while sleeping. Did you add 'while (!current.isInterrupted())' just an another layer of sanity check to make sure it catches interruption?
Christophe Level 22, Lausanne, Switzerland
16 May 2020
There are (of course :-) tools in IntelliJ to follow threads execution and state. Here are some infos from Jetbrains : A starting point for learning Debug Multithreaded Applications. If you put a breakpoint in the main application(-loop) : everything will hangs. You have to play with a (dummy) loop to simulate time passing after launching your threads. But you can focus on a specific thread by putting breakpoints inside thread codes (even conditional breakpoint). In that manner the rest of you application (ie main(){...} ) continue his execution even the others thread Right click on breakpoint to edit properties : Breakpoints In my IntelliJ I had to activate the "Threads" view in the debugger.
Manish Sinha Level 26, london, United Kingdom
17 April 2020
Thanks Codegym for this awesome explanation. Now , I could say this helps me understand more about Interrrupt() and isInterrupted() methods.
13 April 2020
Great lesson :)