Multi-threading part 4

In the previous post we saw about priorities of a thread and how are they defined and handled. In this post we will see what are yield(), join() and sleep() methods. We will also look at the lifecycle of a thread in its entirety.

yield() method

Let us take the same old example to understand the working of yield() method.

class MyThread extends Thread{
    @Override
    public void run(){
        // Below for loop is called job of a thread and it is executed by child thread
        for(int i = 0; i < 3; i++){
            System.out.println("child Thread");
            Thread.yield();
        }
    }
}

class ThreadDemo{
    public static void main(String[] args){
        MyThread t1 = new MyThread(); // Thread instantiation done by main thread. This is the reason t1 becomes child thread.
        t1.start(); // Starting of a thread.
        for(int i = 0; i < 3; i++)
            System.out.println("main thread"); // executed by main thread.
    }
}

In the above program, if we are commenting Thread.yield(), then both threads will be executed simultaneously and we cannot expect which thread will complete first.

If we are not commenting Thread.yield(), then child thread always calls yield() and because of that main thread will get chance more number of times and the chance of completing main thread first is high.

NOTE: Some platforms will not provide proper support for yield().

join() method

If a thread wants to wait until completing some other thread, then we should go for join() method. for example, if a thread t1 wants to wait until completing t2, then t1 has to call t2.join(). If t1 executes t2.join(), then immediately t1 will enter into waiting state until t2 completes. Once t2 completes, then t1 can continue its execution. Various prototypes of join() is:

public final void join()throws InterruptedException

public final void join(long msec)throws InterruptedException

public final void join(long msec, int ns)throws InterruptedException

NOTE: Every join() method throws InterruptedException which is a checked exception. Hence, we need to handle this exception compulsorily either by using try-catch or by using throws keyword, otherwise we will get compile-time error.

Important case studies

Case 1: Waiting of main thread until completing child thread

class MyThread extends Thread{
    public void run(){
        for(int i = 0; i < 3; i++){
            System.out.println("A thread");
            try{
                Thread.sleep(2000);
            }catch(InterruptedException e){}
        }
    }
}

class ThreadJoinDemo{
    public static void main(String[] args)throws InterruptedException{
        MyThread t = new MyThread();
        t.start();
        t.join();
        // t.join(10000);
        for(int i = 0; i < 3; i++){
            System.out.println("main thread");
        }
    }
}

Case 2: Waiting of child thread until completing main Thread

class MyThread extends Thread
{
    static Thread mainThread;
    public void run(){
        try{
            mainThread.join(); // child thread waits for main thread to complete
        }catch(InterruptedException e){}
        for(int i = 0; i < 3; i++){
            System.out.println("Child Thread");
        }

    }
}

class ThreadJoinDemo{
    public static void main(String[] args)throws InterruptedException{
        MyThread.mainThread = Thread.currentThread();
        MyThread t = new MyThread();
        t.start();
        for(int i = 0; i < 3; i++){
            System.out.println("Main Thread");
            Thread.sleep(2000);
        }
    }
}

Case 3: When main and child thread call join on each other

class MyThread extends Thread
{
    static Thread mainThread;
    public void run(){
        try{
            mainThread.join(); // child thread waits for main thread to complete
        }catch(InterruptedException e){}
        for(int i = 0; i < 3; i++){
            System.out.println("Child Thread");
        }

    }
}

class ThreadJoinDemo{
    public static void main(String[] args)throws InterruptedException{
        MyThread.mainThread = Thread.currentThread();
        MyThread t = new MyThread();
        t.start();
        t.join();
        for(int i = 0; i < 3; i++){
            System.out.println("Main Thread");
            Thread.sleep(2000);
        }
    }
}

Case 4: When a thread applies join on itself

class Test{
    public static void main(String[] args)throws InterruptedException{
        Thread.currentThread().join();
    }
}

sleep() method

If a thread don’t want to perform any operation for a particular amount of time, then we should go for sleep() method.

public static native void sleep(long msec)throws InterruptedException

public static void sleep(long msec, int ns)throws InterruptedException

NOTE: Every sleep() method throws InterruptedException, which is a checked exception and therefore, whenever we are using sleep() method we should handle InterruptedException either by try-catch or by throws keyword compulsorily otherwise we will get compile time error.

Let us take a demo example to understand the sleep() method.

class SlideRotator{
    public static void main(String[] args)throws InterruptedException{
        for(int i = 1; i<= 3; i++){
            System.out.println("Slide-" + i);
            Thread.sleep(5000);
        }
    }
}

interrupt() method

A thread can interrupt a sleeping thread or a waiting thread by using interrupt() method of Thread class.

public void interrupt()

Let us look at an example to know how can we apply this method to interrupt a thread.

class MyThread extends Thread{
    public void run(){
        try{
            for(int i = 0; i < 3; i++){
                System.out.println("I am a lazy thread.");
                Thread.sleep(2000);
            }
        }catch(InterruptedException e){
            System.out.println("I got interrupted.");
        }
    }
}
class ThreadInterruptDemo{
    public static void main(String[] args){
        MyThread t = new MyThread();
        t.start();
        t.interrupt(); // main thread executes this line
        System.out.println("End of main");
    }
}

NOTE: Whenever we are calling interrupt() method and if the target thread is not in sleeping or waiting state, then there is no impact of interrupt call immediately. Interrupt call will be waited until target thread enters into sleeping or waiting state. If the target thread enters into sleeping or waiting state, then immediately interrupt call will interrupt the target thread.

If the target thread never entered into sleeping or waiting state in its life-time in its lifetime, then there is no impact of interrupt call. This is the only case where interrupt call will be wasted.

class MyThread extends Thread{
    public void run(){
        for(int i = 1; i <= 5000; i++){
            System.out.println("I am a lazy thread-" + i);
        }
        System.out.println("I am entering into sleeping state.");
        try{
            Thread.sleep(10000);
        }catch(InterruptedException e){
            System.out.println("I got interrupted.");
        }
    }
}
class ThreadInterruptDemo{
    public static void main(String[] args){
        MyThread t = new MyThread();
        t.start();
        t.interrupt(); // main thread executes this line
        System.out.println("End of main");
    }
}

Conclusion[tl;dr]

Property yield() join() sleep()
PURPOSE If a thread wants to pause its execution to give the chance for remaining threads of same priority. If a thread wants to wait until completing some other thread. If a thread do not want to perform any operation for a particular amount of time.
IS IT OVERLOADED? NO YES YES
IS IT FINAL? NO YES NO
DOES IT THROWS InterruptedException? NO YES YES
IS IT NATIVE METHOD? YES NO sleep(long msec) is native but sleep(long msec, int ns) is not native
IS IT STATIC? YES NO YES

This was all about yield(), join() and sleep() methods of Threadclass. In further upcoming blogs I’ll share my insights on one of most important and fun topic in multi-threading i.e. synchronization.