Category: Concurrency

CountDownLatch in Java Concurrency

What is CountDownLatch?

In CountDownLatch, it enables one thread (calling thread) to wait until other threads completes their tasks.

e.g. Assume that a situation where the application’s main thread want to wait until other service threads have completed their works. (media player will wait until the file is loaded, initialized and making ready for the playing)

CountDownLatch works by having a counter initialized with number of threads, which is decremented each time a thread complete its execution (by calling countDown() method available in the CountDownLatch class). When count reaches to zero, it means all threads have completed their execution, and the thread waiting on latch (caller thread)  resume its execution.

 

How CountDownLatch works?

CountDownLatch.java class defines one constructor inside:

public CountDownLatch(int count) {...}

This will create a CountDownLatch that will wait until the given number of thread completes their executions.

e.g:-

CountDownLatch latch1 = new CountDownLatch(4);
latch1.await();

The latch1.await()  hold the currently running thread until 4 threads have completed their execution with latch1. each completion is acknowledged to latch1 with countDown() method.

 This count is essentially the number of threads, for which latch should wait. This value can be set only once, and CountDownLatch provides no other mechanism to reset this count. (You cannot reset or change this value later)

The first interaction with CountDownLatch is made by the main thread (caller thread) which is going to wait for other threads.

This main thread (caller thread) must call, CountDownLatch.await() method immediately after starting other threads. Then await() method will hold the execution of the caller thread until all the given threads are executed. The execution of the await() method will be expired once the count of the CountDownLatch is zero and the caller method will be resumed.

(as i have mentioned earlier, each thread should call the countDown() method on the latch upon completion of the thread. each countDown() call will decrement the count value by one)

 

CountdownLatch_example.png

Lets look at the diagram in detailed.

ThreadA (the main thread) has created a CountDownLatch that should wait for  3 number of threads.

ThreadA has created another three threads and started them. As soon as they are started,  ThreadA call the await() method of the CountDownLatch.

The await() method holds the execution of the caller method (that is ThreadA) until the specified number of threads (In this case three threads) are completed (in the CountDownLatch).

Each thread should call the countDown() method of the CountDownLatch upon completion of its execution.  countDown() method will decrement the count value of the CountDownLatch by one.

As soon as the count is zero, CountdownLatch get to know that all the threads has completed their tasks. Therefore the caller thread (ThreadA) that is waiting on the CountDownLatch will be resumed.

 

Now lets look at the code implementation for the above scenario.

class WorkerThread implements Runnable
{
private String name;
private CountDownLatch countDownLatch;
WorkerThread(String name, CountDownLatch countDownLatch)
{
this.name = name;
this.countDownLatch = countDownLatch;
}
@Override
public void run()
{
try {
Thread.sleep(5000);
System.out.println(" thread [" + name + "] completed ");
countDownLatch.countDown();
} catch (InterruptedException ex) {
System.out.println(" sleeping thread get interrupted ");
}
}
}

view raw
WorkerThread.java
hosted with ❤ by GitHub

 

WorkerThread has been implemented in a way to sleep for 5 seconds. After that it will print the name property and call the countDown() method of the CountDownLatch.

 

public class Application
{
public static void main(String[] args) throws Exception
{
System.out.println(" main thread has started ");
CountDownLatch countDownLatch = new CountDownLatch(4);
WorkerThread workerThread1 = new WorkerThread("thread1", countDownLatch);
WorkerThread workerThread2 = new WorkerThread("thread2", countDownLatch);
WorkerThread workerThread3 = new WorkerThread("thread3", countDownLatch);
WorkerThread workerThread4 = new WorkerThread("thread4", countDownLatch);
new Thread(workerThread1).start();
new Thread(workerThread2).start();
new Thread(workerThread3).start();
new Thread(workerThread4).start();
System.out.println(" all the worker threads have been started. next calling await() method ");
countDownLatch.await();
System.out.println(" Resume the main thread after executing all worker threads");
}
}

view raw
Application.java
hosted with ❤ by GitHub

 

After executing the above Application, you will get the following output.

 main thread has started 
 all the worker threads have been started. next calling await() method 
 thread [thread2] completed 
 thread [thread4] completed 
 thread [thread3] completed 
 thread [thread1] completed 
 Resume the main thread after executing of all worker threads

 

 

 

 

Java – Thread : run() or start() method?

If you just invoke run() directly, it’s executed on the calling thread, just like any other method call.

Thread.start() will create a new thread so that the runnable’s run method is executed in parallel.

when program calls start() method a new Thread is created and code inside run() method is executed in new Thread while if you call run() method directly no new Thread is created and code inside run() will execute on currently running (existing) Thread.

Another difference between start() vs run()  in Java thread is that you cannot call start() method more than one time on thread object. once started, second call of start() will throw IllegalStateException in Java while you can call run() method any number of times.

Starting and Running Thread in java

How to create Thread in Java?

There are two ways to create a Thread in java.

  • Create a subclass of the Thread class and override the run() method.
  • Create a class that implements the Runnable interface and implements the run()  method.  After that an instance of Thread class is created by passing the instance of implemented Runnable interface.

Lets look at those two methods in detailed.

 

Creating a sub class of Thread class

Create a sub class of a Thread class and override the run() method. Then create an object of  the class and call the start() method. Then it will be executed in a separate thread.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Application
{
private final static Logger logger = LoggerFactory.getLogger(Application.class);
public static void main(String[] args) throws Exception
{
logger.info("Application Running on : [{}]", Thread.currentThread().getName());
new MyThread().start();
}
}
class MyThread extends Thread
{
private final static Logger logger = LoggerFactory.getLogger(MyThread.class);
@Override
public void run()
{
logger.info("MyThread Running on : [{}]", Thread.currentThread().getName());
}
}

view raw
Application.java
hosted with ❤ by GitHub

If you check the console log, you will notice that MyThread is running in a different Thread from the main thread.

12:57:40.208 [main] INFO com.springbootdev.samples.springbootasynctask.stream.Application - Application Running on : [main]
12:57:40.223 [Thread-0] INFO com.springbootdev.samples.springbootasynctask.stream.MyThread - MyThread Running on : [Thread-0]

 

Implementing the Runnable interface

In this way, create a class that implements the Runnable interface and implement the run() method. Then create an instance of Thread class by passing the just created runnable instance.  Then call the start() method. We will modify the above example again to demonstrate how the Thread works with Runnable interface.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Application
{
private final static Logger logger = LoggerFactory.getLogger(Application.class);
public static void main(String[] args) throws Exception
{
logger.info("Application Running on : [{}]", Thread.currentThread().getName());
MyWork work = new MyWork();
new Thread(work).start();
}
}
class MyWork implements Runnable
{
private final static Logger logger = LoggerFactory.getLogger(MyWork.class);
@Override
public void run()
{
logger.info("MyWork Running on : [{}]", Thread.currentThread().getName());
}
}

view raw
Application.java
hosted with ❤ by GitHub

 

If you check the console log, you will notice that MyWork is running in a different Thread from the main thread.

12:57:40.208 [main] INFO com.springbootdev.samples.springbootasynctask.stream.Application - Application Running on : [main]
12:57:40.223 [Thread-0] INFO com.springbootdev.samples.springbootasynctask.stream.MyWork - MyWork Running on : [Thread-0]

 

What is the best way to create and run threads?  Sub class of Thread or implementation of Runnable interface?

Any of above approaches can be used to create and run Thread in java. The choice between one of them can be made depends on the personal preferences and special requires.  for instance, if you need to override the some of the default behavior of the Thread class, then you can go with extending Thread class. otherwise you can go with implementing Runnable interface.

Personally i prefer, implementing the Runnable interface and delegating the runnable instance to the Thread object.

 

Worker and Work (Work to be Done)

The relationship between Thread and Runnable can be describes as the relationship between worker and work to be done.

Runnable – Work to be done

Thread  – Worker who is handling the work (Runnable)

 

Executing the run() method directly without executing the start() method

If you just invoke run() directly, it’s executed on the calling thread, just like any other method call.

Thread.start() will create a new thread so that the runnable’s run method is executed in parallel.

when program calls start() method a new Thread is created and code inside run() method is executed in new Thread while if you call run() method directly no new Thread is created and code inside run() will execute on currently running (existing) Thread.

Another difference between start() vs run()  in Java thread is that you cannot call start() method more than one time on thread object. once started, second call of start() will throw IllegalStateException in Java while you can call run() method any number of times.

Please refer the below example.

 

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Application
{
private final static Logger logger = LoggerFactory.getLogger(Application.class);
public static void main(String[] args) throws Exception
{
logger.info("Application Running on : [{}]", Thread.currentThread().getName());
MyThread work = new MyThread();
//directly calling the run() method
work.run();
}
}
class MyThread extends Thread
{
private final static Logger logger = LoggerFactory.getLogger(MyThread.class);
@Override
public void run()
{
logger.info("MyWork Running on : [{}]", Thread.currentThread().getName());
}
}

view raw
Application.java
hosted with ❤ by GitHub

 

If you check the console log, you will notice that MyThread is running in the same thread (main thread).

04:31:55.412 [main] INFO com.springbootdev.samples.springbootasynctask.stream.Application - Application Running on : [main]
04:31:55.419 [main] INFO com.springbootdev.samples.springbootasynctask.stream.MyThread - MyThread Running on : [main]

 

Creating a Thread in Java 8 with Lambda

Runnable interface is marked as a functional interface. Therefore we can use a lambda expression to create a thread as follows.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Application
{
private final static Logger logger = LoggerFactory.getLogger(Application.class);
public static void main(String[] args) throws Exception
{
logger.info("Application Running on : [{}]", Thread.currentThread().getName());
Thread work = new Thread(() > {
logger.info(" Runnable instance running on : [{}] ", Thread.currentThread().getName());
});
work.start();
}
}

view raw
Application.java
hosted with ❤ by GitHub

 

Execution of above program will give you the following console output.

04:37:24.334 [main] INFO com.springbootdev.samples.springbootasynctask.stream.Application - Application Running on : [main]
04:37:24.412 [Thread-0] INFO com.springbootdev.samples.springbootasynctask.stream.Application - Runnable instance running on : [Thread-0]

 

Thread.currentThread()

Thread.currentThread() will return the currently running thread object.

Thread thread = Thread.currentThread();

 

 

 

 

Java Concurrency: ScheduledExecutorService

The ScheduledExecutorService is an extended interface of ExecutorService. It is used to executes after given initial delay or execute tasks repeatedly with given intervals or both (both initial delay and repeatedly execution).  It will repeatedly execute the task until it is explicitly stopped.

 

Different thread pool implementations

  • Single Thread for handling task. (with all repeated executions)
Executors.newSingleThreadScheduledExecutor();

As the name implies this will create only a single worker thread and it will be reused for all repeated execution.

Please refer the below example.

import java.util.concurrent.*;
public class Application
{
public static void main(String[] args) throws InterruptedException
{
System.out.println("main thread is started");
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
scheduledExecutorService.scheduleAtFixedRate(() > {
System.out.println("Thread [" + Thread.currentThread().getName() + "] is executing the task");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("sleeping thread get interrupted");
}
}, 5, 2, TimeUnit.SECONDS);
}
}

view raw
Application.java
hosted with ❤ by GitHub

The initial delay is 5 seconds and the interval between each execution is 2 seconds.

 

  • Thread pool for handling task (with repeated executions)
Executors.newScheduledThreadPool(5);

This will create a thread pool with five threads and those threads will be reused for all repeated execution. Each repeated execution will be handled by a randomly selected thread from the available thread pool.

Please refer the below example.

import java.util.concurrent.*;
public class Application
{
public static void main(String[] args) throws InterruptedException
{
System.out.println("main thread is started");
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);
scheduledExecutorService.scheduleAtFixedRate(() > {
System.out.println("Thread [" + Thread.currentThread().getName() + "] is executing the task");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("sleeping thread get interrupted");
}
}, 5, 2, TimeUnit.SECONDS);
}
}

view raw
Application.java
hosted with ❤ by GitHub

 

 

Java Concurrency: ExecutorService (A better way of asynchronous tasks handling)

The Traditional/Conventional way of handling asynchronous tasks with Thread class

When you develop a multi-threaded java application, you create a Runnable instance and corresponding Thread instance for executing them.  This is the most common and preferred way of doing concurrent programming among most of the developers. Dealing with Thread class directly may lead to few issues and those will be described below.

The issues with dealing with Thread class directly. 

The creation of new thread for each task is really expensive. This is because it involves few steps with managing the lifecycle of the Thread.  It needs to be created, started and  the entire lifecycle of the thread instance should be managed. This consumes more time and system resources. When the number of tasks are increasing/becoming high, the number of threads that need to be created will also be high.

In addition, working directly with Thread class can be error-prone. For instance, if some any error/exception occurs, it is hard to handle them with Thread class. This is because the run() method does not throw any exception. On the other hand, there is no way to check whether the thread has executed successfully because, run() method does not return anything (return type of run() method is void).

When the thread object is started, there is no way to control its behavior. Simply, there is no way to suspend its execution later. (If there is a situation to suspend the execution of some started threads, we cannot do it if we manually created and started threads). even if there are suspend() and stop() methods available in Thread class, those have been deprecated now.

The Solution

Maintaining and managing a pool of  threads that can be used to handle/execute the submitted tasks. The thread pool can be reused to handle the upcoming tasks without creating new threads for each request. This will help to reduce the number of threads created.

Find a way to throw exception and  return the output after the execution. This is possible with Callable and Future. Callable supports throwing exception from run() method and returning output with Future interface.

A Better solution with ExecutorService

ExecutorService is a higher level replacement for working with threads directly.  This is capable of executing tasks asynchronously (in background) with managed thread pool. The main advantage of ExecutorService over traditional Thread class is that,it maintains a pool of worker threads and re-use them for executing tasks (in the background). Once the execution of the task is completed, the worker thread will not go to dead state and it will come back to the pool for serving next available task. Therefore it eliminates the unnecessary cost and overhead associated with creating separate new thread for each task in traditional Thread class approach.

The ExecutorService has some useful methods which accept either Runnable or Callable instances as method parameters. The most of the methods support of returning the output that is wrapped by Future interface. Therefore the calling process(caller) can know the ultimate execution status/result of the background task.

The  ExecutorService has some methods like shutDown() and shutDownNow(). Those methods will help to control/manage the ExecutorService with already submitted and running tasks.

What are the Executor, ExecutorService and Executors?

Executor is the top level interface and ExecutorService is an extended interface of it. Executors is an utility class which has few factory methods for creating different executor services with different types of thread pools.

Here is just a class and interface level representation.

Screen Shot 2017-12-27 at 10.32.51 PM.png

Click here to view the ScheduledExecutorService article.

ThreadPoolExecutor is almost similar to the ExecutorService. 

What are the different types of executor services available?

  • ExecutorService
  • ScheduledExecutorService
  • ThreadPoolExecutor

ExecutorService with different Thread Pool implementations.

 

  • Single Thread for handling all the tasks.
   Executors.newSingleThreadExecutor();

 

Please refer the below code example for Executors.newSingleThreadExecutor();

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
public class Application {
public static void main(String[] args) throws InterruptedException {
System.out.println("main thread is started");
ExecutorService executorService = Executors.newSingleThreadExecutor();
CountDownLatch countDownLatch = new CountDownLatch(10);
List<Callable<String>> allCallableList = new ArrayList<>();
for (int taskIndex = 0; taskIndex < 10; taskIndex++) {
//creating the callable object
Callable<String> callable = () > {
System.out.println("Thread [" + Thread.currentThread().getName() + "] is executing the task");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("sleeping thread get interrupted");
}
countDownLatch.countDown();
return "done";
};
allCallableList.add(callable);
}
//execute all the callables in background threads
executorService.invokeAll(allCallableList);
countDownLatch.await();
System.out.println("main thread completed ");
}
}

view raw
Application.java
hosted with ❤ by GitHub

If you run the above program, you will notice that it will create just a single thread and reuse it for executing all the submitted callable objects.

 

  • Fixed number of threads for handling all tasks
   Executors.newFixedThreadPool(5); // This will create a thread pool with 5 threads. 

 

Please refer the below code example for Executors.newFixedThreadPool(5);

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
public class Application {
public static void main(String[] args) throws InterruptedException {
System.out.println("main thread is started");
ExecutorService executorService = Executors.newFixedThreadPool(5);
CountDownLatch countDownLatch = new CountDownLatch(10);
List<Callable<String>> allCallableList = new ArrayList<>();
for (int taskIndex = 0; taskIndex < 10; taskIndex++) {
//creating the callable object
Callable<String> callable = () > {
System.out.println("Thread [" + Thread.currentThread().getName() + "] is executing the task");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("sleeping thread get interrupted");
}
countDownLatch.countDown();
return "done";
};
allCallableList.add(callable);
}
//execute all the callables in background threads
executorService.invokeAll(allCallableList);
countDownLatch.await();
System.out.println("main thread completed ");
}
}

view raw
Application.java
hosted with ❤ by GitHub

If you run the above program, you will notice that there are only five threads in the thread pool. those threads will be reused to execute all the tasks. No additional threads will be created and the available five threads will be reused.

 

  • Creating new threads as needed (based on the demand) and re-using the previously constructed threads when they are available.
   Executors.newCachedThreadPool();

 

Please refer the below code example for Executors.newCachedThreadPool();

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
public class Application {
public static void main(String[] args) throws InterruptedException {
System.out.println("main thread is started");
ExecutorService executorService = Executors.newCachedThreadPool();
CountDownLatch countDownLatch = new CountDownLatch(10);
List<Callable<String>> allCallableList = new ArrayList<>();
for (int taskIndex = 0; taskIndex < 10; taskIndex++) {
//creating the callable object
Callable<String> callable = () > {
System.out.println("Thread [" + Thread.currentThread().getName() + "] is executing the task");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("sleeping thread get interrupted");
}
countDownLatch.countDown();
return "done";
};
allCallableList.add(callable);
}
//execute all the callables in background threads
executorService.invokeAll(allCallableList);
countDownLatch.await();
System.out.println("main thread completed ");
}
}

view raw
Application.java
hosted with ❤ by GitHub

Controlling the ExecutorService

shutdown() :- The ExecutorService will not accept any new tasks once the shutdown method is called. All the previous submitted tasks will be executed before shut downing the executorService.

shutdownNow() :- The ExecutorService will be shutdown immediately by terminating already running tasks. The tasks that are pending on execution will no be executed and will be returned back as a list. So it is guaranteed that calling this method will shut down the ExecutorService immediately.

 

Either Runnable or Callable instances (Single Object or List of Objects)  will be accepted as method arguments by the execution related methods in the ExecutorService.  If you want to access the currently running thread, you can get it by Thread.currentThread() and it will return the current worker thread.

 

Java Thread: Lifecycle of Thread

The lifecycle of the Thread can be described as follows.

Screen Shot 2017-12-24 at 4.41.24 AM.png

According to the above diagram, a Thread object can be in one of the following life cycle statuses.

 

New

When the thread object is created it is in the new state.

Thread threadA = new Thread();

Now the threadA is in the new state.

 

Runnable

This is commonly known as “ready to run state“. Here the thread object is started and ready to run. There will be multiple thread objects in this state and it it the responsibility of the Thread scheduler to select a thread object for running. The thread object in new state can be moved to Runnable state by calling the start() method on it.

threadA.start();

 

Thread object can be started only once. if you try to start it more than once,  it will throw IllegalThreadStateException.

 

Running

If the Thread scheduler has selected a thread from runnable state and call the run() method, then it is in the Running state. Here the run() method is still executing and not competed yet. It is important to note that the run() method must be called by the Thread scheduler.

 

Not Runnable

This is also known as blocking, sleeping or waiting state. The currently running thread can be moved to “Not Runnable State” due to several reasons.  for instance

  • calling the sleep() method
  • calling the wait() method on the shared resource
  • calling the join() method etc….

In this case, the execution of the running thread might be hold and moved to not runnable state from running state.

 

Back to Runnable from Not Runnable state

The threads that are in the not runnable state can be moved to runnable state again on following situations.

  • sleeping/waiting time has expired
  • call the interrupt() method
  • call the notify()/notifyAll() on waited resource/object

After  it is moved back to the runnable state, it is the responsibility of the thread scheduler to select them and resume their execution.

 

Dead

Once the run() method is completed, the execution of the thread object will be over and thread will be moved to the dead state.

 

 

 

Java Thread: yield() method example

Thread.yield()

This is a static method available in thread class and give the hint for the thread scheduler that the currently running thread is willing to yield the execution time for some other thread.

Thread.yield() will just give a recommendation/hint for the thread scheduler and it is up to thread scheduler to accept or ignore. Therefore we cannot guarantee that calling the Thread.yield() will immediately move the currently running thread not “Not Running  state” and allow some other thread to utilize the CPU time. It will be decided by the thread scheduler.

Please refer the below example about Thread.yield()

 

public class Application
{
public static void main(String[] args)
{
System.out.println("main thread is started");
ThreadA threadA = new ThreadA();
threadA.start();
ThreadB threadB = new ThreadB();
threadB.start();
System.out.println("main thread completed");
}
}
class ThreadA extends Thread
{
public void run()
{
System.out.println("ThreadA is running");
for(int index=0;index<5;index++)
{
System.out.println("ThreadA running on ["+index+"]");
if(index==2){
System.out.println("ThreadA calls Thread.yield() ");
Thread.yield();
}
}
System.out.println("ThreadA completed");
}
}
class ThreadB extends Thread
{
public void run()
{
System.out.println("ThreadB is running");
for(int index=0;index<5;index++){
System.out.println("ThreadB running on ["+index+"]");
}
System.out.println("ThreadB completed");
}
}

view raw
Application.java
hosted with ❤ by GitHub

 

It is very difficult to give the exact output upon running the above code sample as the Thread.yield() method is not guaranteed to run.  Therefore if you run above program few times, you might get different results.

 

 

 

Java Thread : Difference between wait(), join() and sleep()

wait()

The call of wait() method on the object will hold the execution of the currently running thread until some other thread calls the notify() or notifyAll() method on the same object. The currently running thread will release the object monitor of the object on which the wait() method is invoked/called. Then some other thread can acquire the object monitor and continue its work with that object. The thread (that owns the object monitor) will call the notify() or notifyAll() method to notify the threads that are waiting on the on that object to inform that the object monitor will be released soon and get ready to acquire it.

wait() method should be called in a synchronized context. that means either in synchronized method or synchronized block.

since the wait() method is inherited from the Object class, it can be invoked on any java object(that is directly or indirectly inherited from Object class)

Click here to see my blog article about wait() method with code examples.

 

join()

The join() method belongs to the Thread class. therefore join() method can be invoked only on the Thread objects. The join() method is used to postpone the execution of the currently running thread after the execution of some other thread.

ThreadA threadA =  new ThreadA();
threadA.join();

Here the currently running thread (lets say it as the main thread)  will hold the execution until the threadA completes. Once the threadA is completed, the waiting/sleeping thread (the main thread) will be resumed its execution.  Simply the main thread will be resumed once the threadA  is dead(after completing the run method)

Click here to see my blog article about join() method with code examples.

 

sleep()

Thread.sleep causes the current thread to suspend execution for a specified time period. This is an efficient means of making processor time available to the other threads of an application or other applications that might be running on a computer system.

Click here to see my blog article about sleep() method with code examples

 

The more comparison of wait(), sleep() and join method can be found on my next blog article.

 

Java Thread: Comparison of wait(), sleep() and join() methods

 

sleep() is a method which is used to hold the process for few seconds or the time you wanted but in case of wait() method thread goes in waiting state and it won’t come back automatically until we call the notify() or notifyAll().

The major difference is that wait() releases the lock or monitor while sleep() and join() doesn’t releases any lock or monitor while waiting. wait() is used for synchronizing the access for the shared object in multi-threaded environment and will be used in inter-threaded communication. sleep is used to pause the execution on currently thread for a defined time period.

Thread.sleep() sends the current thread into the “Not Runnable” state for some amount of time. The thread keeps the monitors it has acquired.

i.e. if the thread is currently in a synchronized block or method no other thread can enter this block or method. If another thread calls t.interrupt() it will wake up the sleeping thread. Note that sleep is a static method, which means that it always affects the current thread (the one that is executing the sleep method). A common mistake is to call t.sleep() where t is a different thread; even then, it is the current thread that will sleep, not the t thread.

object.wait() sends the current thread into the “Not Runnable” state, like sleep(), but with wait() is called on an object, not a thread; we call this object the “lock object.”

Before lock.wait() is called, the current running thread must synchronize on the lock object; wait() then releases this lock, and adds the thread to the “wait list” associated with the lock. Later, another thread can synchronize on the same lock object and call lock.notify(). This wakes up the original, waiting thread. Basically, wait()/notify() is like sleep()/interrupt(), only the active thread does not need a direct pointer to the sleeping thread, but only to the shared lock object.

thread.join() sends the current running thread into the “Not Runnable” state, until joined thread is completing its execution. once the joined thread completes its execution, the waiting thread will comes back to the runnable state. Then the waiting thread will be resumed again. join() method will not release any monitor or lock object acquired by the running thread and it will be waiting with those monitors(if there is any)

The wait() method must be called in a synchronized context, but sleep() and join() methods does not require to be.Thread.join() waits for the thread to completely finish, whereas a synchronized block can be used to prevent two threads from executing the same piece of code at the same time.

It is recommended, not use waitnotify or notifyAll on Thread instances. They should be used on objects for synchronizing the access among the multiple threads.

 

Lets compare each of these methods in detailed.

Derived from or Belongs to:

  • wait(): Object class
  • sleep(): Thread class
  • join():  Thread class

Call/Invoked on:

  • wait(): Call on an object; current thread must synchronize on the lock object.
  • sleep(): Call on a Thread; always currently executing thread will be sleep.
  • join():  Call on a Thread. currently executing thread will be joined at the end of the execution of the calling thread.

Synchronized Context:

  • wait(): must be called in a synchronized context. (either in synchronized block or method)
  • sleep(): synchronization context not required
  • join(): synchronization context not required

Hold lock/monitor:

  • wait(): release the object monitor for giving the chance for other threads to execute.
  • sleep(): keep object monitor for at least the timeout specified or somebody interrupt.
  • join(): keep the monitor and goes to sleep until the joined() method completes its execution.

Wake-Up:

  • wait():  Call notify(), notifyAll() on the object.
  • sleep():  After expiring the sleeping time or call interrupt().
  • join():  completing the run method of the joined thread (dead of the joined thread)

Usage:

  • sleep():  for holding the execution of currently running thread for a specific time duration
  • wait(): for multi-thread-synchronization on an shared object.
  • join(): for joining the execution of the currently running thread at the end of the another thread.

What is really happening after waiting or sleeping?

sleep(), wait() and join() method will cause to move the currently running thread from running state to not runnable state (waiting/blocking/sleeping state) . However, the waiting/blocking thread will become runnable after expiring the time duration or calling the relevant method like notify(). notifyAll(), interrupt() etc.  what will be really happening after that?  Will the waiting thread get resumed/run as soon after it wakes up?

The simple answer is NO. The waiting thread will be moved from “Not runnable state” to “runnable state“. After that it is the responsibility of the Thread scheduler to move it to “running state“.  Since the Thread scheduler is working and shifting the execution of thread with milliseconds and nano seconds, we feel like that it just resumed as soon as  it wakes up.

References:

https://howtodoinjava.com/core-java/multi-threading/difference-between-sleep-and-wait/

 

Java Thread: sleep() and interrupt() methods

sleep()

Thread.sleep() method will  hold the execution of the currently running thread for a defined period of time. once the sleeping time os over, it will resume the execution. sleep() method is a static method available in java thread class. unlike wait() method, sleep method will not release any object monitor before going to sleep. it is guaranteed to sleep the thread for a given time period unless some other thread interrupt it (by calling interrupt() method on the thread object).

 

public class Application
{
public static void main(String[] args)
{
System.out.println("main thread is started");
try {
System.out.println("main thread will be slept for 5 seconds");
Thread.sleep(5000);
System.out.println("main thread resumed after sleeping");
} catch (InterruptedException ex) {
System.out.println("sleeping thread get interrupted");
}
System.out.println("main thread completed");
}
}

view raw
Application.java
hosted with ❤ by GitHub

The execution of the above program will produce the following output.

main thread is started
main thread will be slept for 5 seconds
main thread resumed after sleeping
main thread completed

 

As you can see that the main thread is started and sleeping for 5 seconds. The  application(main thread) will sleep for 5 seconds and wake up after sleeping duration over.

 

Interrupting the sleeping thread with interrupt()

The interrupt() method can be called on a sleeping thread object to interrupt its sleep and move back to the runnable state.  The below example will demonstrate how the interrupt() is really working.

public class Application
{
public static void main(String[] args)
{
System.out.println("main thread is started");
ThreadA threadA = new ThreadA();
threadA.start();
ThreadB threadB = new ThreadB(threadA);
threadB.start();
System.out.println("main thread completed");
}
}
class ThreadA extends Thread
{
public void run()
{
System.out.println("ThreadA is running");
try {
System.out.println("ThreadA is sleeping for 15 seconds ");
Thread.sleep(15000);
System.out.println("ThreadA is waked up ");
} catch (InterruptedException e) {
System.out.println("Sleep of ThreadA get interrupted ");
}
System.out.println("ThreadA completed");
}
}
class ThreadB extends Thread
{
private ThreadA threadA;
ThreadB(ThreadA threadA)
{
this.threadA = threadA;
}
public void run()
{
System.out.println("ThreadB is running");
try {
System.out.println("ThreadB is sleeping for 5 seconds");
Thread.sleep(5000);
System.out.println("ThreadB wakes up from sleep and interrupts ThreadA ");
threadA.interrupt();
} catch (InterruptedException e) {
System.out.println("Sleep of ThreadB get interrupted");
}
System.out.println("ThreadB completed");
}
}

view raw
Application.java
hosted with ❤ by GitHub

The main thread creates and starts two thread objects known as threadA and threadBthreadA will be slept for 15 seconds while threadB is slept for 5 seconds. Therefore the threadB is guaranteed to be wake up before threadA wakes up.  Once the threadB wakes up, it interrupts the threadA which is still sleeping. Then the sleeping threadA will get interrupted and  it throws the InterruptedException. The thrown exception will be caught by the catch block and the threadA will be resumed from the catch block.

If you run the above sample program, you will get the following output.

main thread is started
main thread completed
ThreadB is running
ThreadB is sleeping for 5 seconds
ThreadA is running
ThreadA is sleeping for 15 seconds 
ThreadB wakes up from sleep and interrupts ThreadA 
ThreadB completed
Sleep of ThreadA get interrupted 
ThreadA completed