April 01, 2016

Part 3: Java Thread Interview Questions & Answers (Thread lifecycle)

What are the different states of a thread's lifecycle?
  • Runnable: waiting for its turn to be picked for execution by the thread scheduler based on thread priorities.
  • Running: The processor is actively executing the thread code. It runs until it becomes blocked, or voluntarily gives up its turn with this static method Thread.yield(). Because of context switching overhead, yield() should not be used very frequently.
  • Waiting: A thread is in a blocked state while it waits for some external processing such as file I/O to finish.
  • Sleeping: Java threads are forcibly put to sleep (suspended) with this overloaded method: Thread.sleep(milliseconds), Thread.sleep(milliseconds, nanoseconds);
  • Blocked on I/O: Will move to runnable after I/O conditions like reading bytes of data etc changes.
  • Blocked on synchronization: Will move to Runnable when a lock is acquired.
  • Dead: The thread is finished working.

What is the difference between yield() and sleep() methods of thread in Java?
Both yield and sleep are declared on java.lang.Thread class and doesn't release any lock held by the thread.

yield() method pauses the currently executing thread temporarily to give a chance to the remaining waiting threads of the same priority to execute. If there is no waiting thread or all the waiting threads have a lower priority then the same thread will continue its execution. The yielded thread when it will get the chance for execution is decided by the thread scheduler whose behaviour is vendor-dependent.

sleep() allows the thread to go to a sleep state for x milliseconds.

When a task invokes yield(), it changes from a running state to a runnable state. When a task invokes sleep(), it changes from a running state to a waiting/sleeping state.

yield () is typically used in scenarios where a thread decides it doesn't need to use the CPU for a while and is willing to give the CPU to another thread of equal priority. Whereas sleep() is commonly used when you want to introduce a delay in the execution of a thread, perhaps to simulate a wait time or to control the rate at which a thread consumes resources.

The key difference in the context of Java is that yield is about giving up the current thread's use of the processor voluntarily, allowing threads of equal priority to run, while sleep is about intentionally pausing the current thread's execution for a specified duration.

How do you share data between two threads in Java?
wait and notify methods in Java are used for inter-thread communication i.e. if one thread wants to tell something to another thread, it uses notify() and notifyAll() methods of java.lang.Object.

A classical example of the wait-and-notify method is the Producer-Consumer design pattern, where One thread produces and puts something on the shared bucket, and then tells the other thread that there is an item for your interest in the shared object, consumer thread then pick an item and do its job. Without wait() and notify(), the consumer thread needs to be busy checking, even if there is no change in the state of the shared object.

This brings an interesting point on using the wait and notify mechanism, a call to notify() happens when the thread changes the state of the shared object i.e. in this case producer changes the bucket from empty to not empty, and the consumer changes state from non-empty to empty.

Also, the wait and notify method must be called from a synchronized context. A waiting thread may wake up, without any change in its waiting condition due to spurious wakeup. e.g: if a consumer thread, which is waiting because the shared queue is empty, wakes up due to a false alarm and tries to get something from the queue without further checking whether the queue is empty or not then an unexpected result is possible.

What is the difference between notify and notifyAll in Java?
notify will only notify one Thread and notifyAll method will notify all Threads which are waiting on that monitor or lock.

When you call notify only one of the threads, which is in a waiting state will be woken. However, it's not guaranteed which thread will be woken, because it depends on upon Thread scheduler.

While if you call the notifyAll method, all threads waiting on that lock will be woken up, but again all woken threads will fight for the lock before executing the remaining code. That's why the wait is called on loop because if multiple threads are woken up, the thread which will get lock will first execute and it may reset the waiting for condition, which will force subsequent threads to wait.

Why wait, notify, and notifyAll methods are not inside the thread class? 
Java provides lock at the object level, not at the thread level that's why wait, notify and notifyAll methods are defined in the Object class. Every object has a lock, which is acquired by a thread. Now if the thread needs to wait for a certain lock it makes sense to call wait() on that object rather than on that thread.

If the wait() method was declared on the Thread class, it was not clear which lock thread was waiting. In short, since wait, notify, and notifyAll operate at lock level, it makes sense to define it on object class because lock belongs to the object.

Why wait and notify methods are called from the synchronized block?
In Java, the wait() and notify() methods are used for inter-thread communication and synchronization. These methods are designed to work with the monitor mechanism provided by Java to ensure that threads can safely coordinate and communicate with each other.

Let us first understand the monitor mechanism. Every object created in Java has one associated monitor (mutually exclusive lock). Only one thread can own a monitor at any given time. For achieving synchronization in Java this monitor is used. When any thread enters a synchronized method/block it acquires the lock on the specified object. When any thread acquires a lock it is said to have entered the monitor. All other threads which need to execute the same shared piece of code (locked monitor) will be suspended until the thread which initially acquired the lock releases it.

The wait method tells the current thread (the thread that is executing code inside a synchronized method or block) to give up the monitor and go to the waiting state. notify method wakes up a single thread that is waiting on this object's monitor, whereas notifyAll method wakes up all the threads that called wait( ) on the same object.

Placing the wait() and notify() calls inside a synchronized block ensures that the thread invoking these methods owns the monitor of the object. This helps prevent race conditions and ensures that the thread has exclusive access to the shared resource.

The wait() method is used to make a thread wait until another thread invokes notify() or notifyAll() on the same object. This typically happens when a certain condition that the waiting thread is interested in becomes true. The wait() method must be called from within a synchronized block to ensure that the thread releasing the lock (by calling wait()) doesn't interfere with other threads.

The notify() method is used to wake up one of the threads that are currently waiting on the object's monitor. The choice of which thread to wake up is not specified and depends on the scheduling policy. Similarly, the notifyAll() method wakes up all threads that are currently waiting on the object's monitor. Calling notify() or notifyAll() should also be done within a synchronized block to ensure that the calling thread holds the monitor.

If you don't call them from a synchronized context, your code will throw IllegalMonitorStateException. 

What is the difference between wait() and wait(long timeout)?
When the wait() method is called on an object, it causes the current thread to wait until another thread invokes the notify() or notifyAll() method for this object. wait(long timeout) causes the current thread to wait until either another thread invokes the notify() or notifyAll() methods for this object, or a specified timeout time has elapsed.

When the wait() is called on an object, Thread enters from running to the waiting state. It waits for some other thread to call notify so that it can enter the runnable state. When wait(long timeout) is called on an object - Thread enters from running to the waiting state. Then even if notify() or notifyAll() is not called after the timeout time has elapsed thread will go from waiting to a runnable state.

What is the difference between wait() and sleep()?
  • The wait() method belongs to java.lang.Object class, thus can be called on any Object. The sleep() method belongs to java.lang.Thread class, thus can be called on Threads.
  • The wait() method can only be called from a Synchronized context i.e. using synchronized block or synchronized method. The sleep() method can be called from any context.
  • The wait() method releases the lock on an object and gives others a chance to execute. The sleep() method does not release the lock of an object for a specified time or until it is interrupted.
  • A waiting thread can be awakened by notify() or notifyAll() method. Sleeping can be awakened by interrupt or when the time expires.
Why Thread sleep() and yield() methods are static?
Thread sleep() and yield() methods work on the currently executing thread. So there is no point in invoking these methods on some other threads that are in a wait state. That’s why these methods are made static so that when this method is called statically, it works on the currently executing thread and avoids confusion to the programmers who might think that they can invoke these methods on some non-running threads.

How can we make sure main() is the last thread to finish in the Java Program?
We can use the Thread join() method to make sure all the threads created by the program are dead before finishing the main function.

How can you ensure all threads that started from the main must end in the order in which they started and also main should end last?
We can use the join() method to ensure all threads that started from the main must end in the order in which they started and also main should end last. In other words, waits for this thread to die. e.g:

public class MyJoinClass implements Runnable {
    public void run() {
        System.out.println("Inside run(), ThreadName=" + Thread.currentThread().getName());
    }

    public static void main(String... args) throws InterruptedException {
        System.out.println("main() started");
        MyJoinClass runnable = new MyJoinClass();
        Thread thread1 = new Thread(runnable);
        Thread thread2 = new Thread(runnable);

        thread1.start();
        thread1.join();

        thread2.start();
        thread2.join();

        System.out.println("main() ended");
    }
}

With Join:
main() started
Inside run(), ThreadName=Thread-5
Inside run(), ThreadName=Thread-6
main() ended

Without Join:
main() started
Inside run(), ThreadName=Thread-5
main() ended
Inside run(), ThreadName=Thread-6

If you enjoy our content and want to support us, please consider donating via gpay, phonepay or paytm on +91 9920600280. Also, I’d appreciate it if you’d buy me a coffee☕ 


Keep learning and growing!
-K Himaanshu Shuklaa..

No comments:

Post a Comment