Difference between revisions of "Java Threads"

(public final void join(long millisec))
Line 206: Line 206:
 
====public final void '''setDaemon(boolean on)''' ====
 
====public final void '''setDaemon(boolean on)''' ====
 
A parameter of true denotes this Thread as a daemon thread.
 
A parameter of true denotes this Thread as a daemon thread.
====public final void '''join(long millisec)''' ====
+
====public final void '''join(long millisec)''' - t1.join(2000);//start second thread after waiting for 2 seconds or if it's dead ====
 
The current thread invokes this method on a second thread, causing the current thread to block until the second thread terminates or the specified number of milliseconds passes.
 
The current thread invokes this method on a second thread, causing the current thread to block until the second thread terminates or the specified number of milliseconds passes.
 +
 
====public void '''interrupt()''' ====
 
====public void '''interrupt()''' ====
 
Interrupts this thread, causing it to continue execution if it was blocked for any reason.
 
Interrupts this thread, causing it to continue execution if it was blocked for any reason.

Revision as of 10:38, 9 July 2018

Life Cycle of a Thread

Thread_Life_Cycle.jpg

Thread States

Following are the stages of the life cycle

NEW

A new thread begins its life cycle in the new state. It remains in this state until the program starts the thread. It is also referred to as a born thread.

RUNNABLE

After a newly born thread is started, the thread becomes runnable. A thread in this state is considered to be executing its task.

RUNNING

BLOCKED/WAITING

Sometimes, a thread transitions to the waiting state while the thread waits for another thread to perform a task. A thread transitions back to the runnable state only when another thread signals the waiting thread to continue executing.

A runnable thread can enter the timed waiting state for a specified interval of time. A thread in this state transitions back to the runnable state when that time interval expires or when the event it is waiting for occurs.

TERMINATED/DEAD

A runnable thread enters the terminated state when it completes its task or otherwise terminates.


Thread Priorities

Every Java thread has a priority that helps the operating system determine the order in which threads are scheduled.

Java thread priorities are in the range between MIN_PRIORITY (a constant of 1) and MAX_PRIORITY (a constant of 10). By default, every thread is given priority NORM_PRIORITY (a constant of 5).

Threads with higher priority are more important to a program and should be allocated processor time before lower-priority threads. However, thread priorities cannot guarantee the order in which threads execute and are very much platform dependent.

Runnable Interface

Create a Thread by Implementing a Runnable Interface

If your class is intended to be executed as a thread then you can achieve this by implementing a Runnable interface. You will need to follow three basic steps:

  • Step 1:As a first step, you need to implement a run() method provided by a Runnable interface. This method provides an entry point for the thread and you will put your complete business logic inside this method. Following is a simple syntax of the run() method
public void run( )
  • Step 2: As a second step, you will instantiate a Thread object using the following constructor
Thread(Runnable threadObj, String threadName);

Where, threadObj is an instance of a class that implements the Runnable interface and threadName is the name given to the new thread.

  • Step 3:Once a Thread object is created, you can start it by calling start() method, which executes a call to run( ) method. Following is a simple syntax of start() method
void start();

Example:

class RunnableDemo implements Runnable {
   private Thread t;
   private String threadName;
   
   RunnableDemo( String name) {
      threadName = name;
      System.out.println("Creating " +  threadName );
   }
   
   public void run() {
      System.out.println("Running " +  threadName );
      try {
         for(int i = 4; i > 0; i--) {
            System.out.println("Thread: " + threadName + ", " + i);
            // Let the thread sleep for a while.
            Thread.sleep(50);
         }
      } catch (InterruptedException e) {
         System.out.println("Thread " +  threadName + " interrupted.");
      }
      System.out.println("Thread " +  threadName + " exiting.");
   }
   
   public void start () {
      System.out.println("Starting " +  threadName );
      if (t == null) {
         t = new Thread (this, threadName);
         t.start ();
      }
   }
}

public class TestThread {

   public static void main(String args[]) {
      RunnableDemo R1 = new RunnableDemo( "Thread-1");
      R1.start();
      
      RunnableDemo R2 = new RunnableDemo( "Thread-2");
      R2.start();
   }   
}

This will produce the following result

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.

Thread Class

Create a Thread by Extending a Thread Class

The second way to create a thread is to create a new class that extends Thread class using the following two simple steps. This approach provides more flexibility in handling multiple threads created using available methods in Thread class.

  • Step 1:You will need to override run( ) method available in Thread class. This method provides an entry point for the thread and you will put your complete business logic inside this method. Following is a simple syntax of run() method
public void run( )
  • Step 2:

Once Thread object is created, you can start it by calling start() method, which executes a call to run( ) method. Following is a simple syntax of start() method

void start( );

Example

class ThreadDemo extends Thread {
   private Thread t;
   private String threadName;
   
   ThreadDemo( String name) {
      threadName = name;
      System.out.println("Creating " +  threadName );
   }
   
   public void run() {
      System.out.println("Running " +  threadName );
      try {
         for(int i = 4; i > 0; i--) {
            System.out.println("Thread: " + threadName + ", " + i);
            // Let the thread sleep for a while.
            Thread.sleep(50);
         }
      } catch (InterruptedException e) {
         System.out.println("Thread " +  threadName + " interrupted.");
      }
      System.out.println("Thread " +  threadName + " exiting.");
   }
   
   public void start () {
      System.out.println("Starting " +  threadName );
      if (t == null) {
         t = new Thread (this, threadName);
         t.start ();
      }
   }
}

public class TestThread {

   public static void main(String args[]) {
      ThreadDemo T1 = new ThreadDemo( "Thread-1");
      T1.start();
      
      ThreadDemo T2 = new ThreadDemo( "Thread-2");
      T2.start();
   }   
}

This will produce the following result

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.

Thread Methods

public void start()

Starts the thread in a separate path of execution, then invokes the run() method on this Thread object.

public void run()

If this Thread object was instantiated using a separate Runnable target, the run() method is invoked on that Runnable object.

public final void setName(String name)

Changes the name of the Thread object. There is also a getName() method for retrieving the name.

public final void setPriority(int priority)

Sets the priority of this Thread object. The possible values are between 1 and 10.

public final void setDaemon(boolean on)

A parameter of true denotes this Thread as a daemon thread.

public final void join(long millisec) - t1.join(2000);//start second thread after waiting for 2 seconds or if it's dead

The current thread invokes this method on a second thread, causing the current thread to block until the second thread terminates or the specified number of milliseconds passes.

public void interrupt()

Interrupts this thread, causing it to continue execution if it was blocked for any reason.

public final boolean isAlive()

Returns true if the thread is alive, which is any time after the thread has been started but before it runs to completion.




Multithreading Interview Questions and Answers

What is the difference between processes and threads ?

    • A process is an execution of a program, while a Thread is a single execution sequence within a process. A process can contain multiple threads. A Thread is sometimes called a lightweight process.

Explain different ways of creating a thread.Which one would you prefer and why ?

    • There are three ways that can be used in order for a Thread to be created:
      • A class may extend the Thread class.
      • A class may implement the Runnable interface.
    • An application can use the Executor framework, in order to create a thread pool.
    • The Runnable interface is preferred, as it does not require an object to inherit the Thread class. In case your application design requires multiple inheritance, only interfaces can help you. Also, the thread pool is very efficient and can be implemented and used very easily.

Explain the available thread states in a high-level?

    • During its execution, a thread can reside in one of the following states:
      • Runnable: A thread becomes ready to run, but does not necessarily start running immediately.
      • Running: The processor is actively executing the thread code.
      • Waiting: A thread is in a blocked state waiting for some external processing to finish.
      • Sleeping: The thread is forced to sleep.
      • Blocked on I/O: Waiting for an I/O operation to complete.
      • Blocked on Synchronization: Waiting to acquire a lock.
      • Dead: The thread has finished its execution.

What is the difference between a synchronized method and a synchronized block ?

    • In Java programming, each object has a lock. A thread can acquire the lock for an object by using the synchronized keyword. The synchronized keyword can be applied in a method level (coarse grained lock) or block level of code (fine grained lock).
  1. How does thread synchronization occurs inside a monitor ? What levels of synchronization can you apply ?
    • The JVM uses locks in conjunction with monitors. A monitor is basically a guardian that watches over a sequence of synchronized code and ensuring that only one thread at a time executes a synchronized piece of code. Each monitor is associated with an object reference. The thread is not allowed to execute the code until it obtains the lock.

What’s a deadlock ?

    • A condition that occurs when two processes are waiting for each other to complete, before proceeding. The result is that both processes wait endlessly.
  1. How do you ensure that N threads can access N resources without deadlock ?
    • A very simple way to avoid deadlock while using N threads is to impose an ordering on the locks and force each thread to follow that ordering. Thus, if all threads lock and unlock the mutexes in the same order, no deadlocks can arise.


Java Examples - Monitoring a Thread

How to monitor a thread's status?

Following example demonstrates how to monitor a thread's status by extending Thread class and using currentThread.getName() method.

class MyThread extends Thread {
   boolean waiting = true;
   boolean ready = false;
   MyThread() {
   }
   public void run() {
      String thrdName = Thread.currentThread().getName();
      System.out.println(thrdName + " starting.");
      while(waiting) System.out.println("waiting:"+waiting); 
      System.out.println("waiting...");
      startWait(); 
      try {
         Thread.sleep(1000);
      } catch(Exception exc) {
         System.out.println(thrdName + " interrupted.");
      }
      System.out.println(thrdName + " terminating.");
   }
   synchronized void startWait() {
      try {
         while(!ready) wait();
      } catch(InterruptedException exc) {
         System.out.println("wait() interrupted");
      }
   }
   synchronized void notice() {
      ready = true;
      notify();
   }
}
public class new_class {
   public static void main(String args[]) throws Exception {
      MyThread thrd = new MyThread();
      thrd.setName("MyThread #1");
      showThreadStatus(thrd);
      thrd.start();
      
      Thread.sleep(50);
      showThreadStatus(thrd);
      thrd.waiting = false;
      
      Thread.sleep(50); 
      showThreadStatus(thrd);
      thrd.notice();
      
      Thread.sleep(50);
      showThreadStatus(thrd);
      
      while(thrd.isAlive()) 
      System.out.println("alive");
      showThreadStatus(thrd);
   }
   static void showThreadStatus(Thread thrd) {
      System.out.println(thrd.getName()+"  Alive:="+thrd.isAlive()+" State:=" + thrd.getState() );
   }
}


Result

The above code sample will produce the following result.

main Alive=true State:=running


What is wrong with this code? Heap Vs Stack, Thread safety & Synchronized

A very simple code that should print numbers from 7 to 21. But does it?

import java.util.concurrent.TimeUnit;
 
class Counter extends Thread {
 
    //instance variable
    Integer count = 0;
 
    // method where the thread execution will start
    public void run() {
        int fixed = 6;  //local variable
        
        for (int i = 0; i < 3; i++) {
            System.out.println(Thread.currentThread().getName() + ": result=" 
                                  + performCount(fixed)); 
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }  
    }
 
    // let’s see how to start the threads
    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName() + " is executing..." );
        Counter counter = new Counter();
        
        //5 threads
        for (int i = 0; i < 5; i++) {
            Thread t = new Thread(counter);
            t.start();
        }
        
    }
    
    //multiple threads can access me concurrently
    private int performCount(int fixed) {
        return (fixed + ++count);
    }
}


Above code is NOT Thread-safe If you run it multiple times, you will see that some numbers get repeated as shown below. You get five”15″s and three “12”s. The result will be unpredictable and you will get different results each time you run it.

main is executing...
Thread-1: result=7
Thread-2: result=8
Thread-3: result=9
Thread-4: result=10
Thread-5: result=11
Thread-2: result=12
Thread-3: result=12
Thread-4: result=12
Thread-5: result=13
Thread-1: result=14
Thread-2: result=15
Thread-3: result=15
Thread-4: result=15
Thread-5: result=15
Thread-1: result=15


What is happening under the covers in terms of Heap Vs Stack memory & thread-safety

As shown below in the diagaram, the local variable “fixed”, and the reference “counter” to the instance of the class “Counter” are stored in the stack. The instance of “Counter”, i,e. the object itself is stored in the heap. So, it will be shared by all the threads. The “++count” operation is not atomic and performs 3 operations under the covers:

  • Step 1: get value of count from heap
  • Step 2: add 1 to count (i.e. count = count + 1)
  • Step 3: write the new value back to the heap memory

So, it is possible that 5 threads read the same value of say “count = 8” and increment them all to “9”, and then when added with the fixed value of 6, resulting in five “15”s. Each time you run, you get different results. The above code is unpredictable.

HeapVsStackMemory.jpg

How to fix the concurrency issue?

The above thread safety issue can be fixed two ways by controlling the access to the shared object “counter”.

Solution 1: Synchronized i.e. a lock on the performCount() method

This will put a lock on “counter” object so that when one thread is performing the other threads have to wait for the lock.


import java.util.concurrent.TimeUnit;
 
class Counter extends Thread {
 
    //instance variable
    Integer count = 0;
 
    // method where the thread execution will start
    public void run() {
        int fixed = 6;
        
        for (int i = 0; i < 3; i++) {
            System.out.println(Thread.currentThread().getName() + ": result=" 
                                  + performCount(fixed)); 
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }  
    }
 
    // let’s see how to start the threads
    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName() + " is executing..." );
        Counter counter = new Counter();
        
        //5 threads
        for (int i = 0; i < 5; i++) {
            Thread t = new Thread(counter);
            t.start();
        }
        
    }
    
    private synchronized int performCount(int fixed) {
        return (fixed + ++count);
    }
}

Output:

main is executing...
Thread-1: result=7
Thread-3: result=8
Thread-2: result=9
Thread-4: result=10
Thread-5: result=11
Thread-4: result=13
Thread-1: result=12
Thread-2: result=14
Thread-3: result=15
Thread-5: result=16
Thread-4: result=18
Thread-3: result=19
Thread-1: result=20
Thread-5: result=21
Thread-2: result=17

Why is locking of a method for thread safety is called “synchronized” and not “locked”?

When a method or block of code is locked with the reserved “synchronized” key word in Java, the memory (i.e. heap) where the shared data is kept is synchronized. This means,

When a synchronized block or method is entered after the lock has been acquired by a thread, it first reads (i.e. synchronizes) any changes to the locked object from the main heap memory to ensure that the thread that has the lock has the current info before start executing.

After the synchronized block has completed and the thread is ready to relinquish the lock, all the changes that were made to the object that was locked is written or flushed back (i.e. synchronized) to the main heap memory so that the other threads that acquire the lock next has the current info.


Solution 2: AtomicInteger so that the increment operation is atomic

The “incrementAndGet()” on AtomicInteger happens atomically so that two or more threads cannot read the same value and increment them to the same result.

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
 
class Counter extends Thread {
 
    //instance variable
    AtomicInteger count = new AtomicInteger();
 
    // method where the thread execution will start
    public void run() {
        int fixed = 6;
        
        for (int i = 0; i < 3; i++) {
            System.out.println(Thread.currentThread().getName() + ": result=" 
                                  + performCount(fixed)); 
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }  
    }
 
    // let’s see how to start the threads
    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName() + " is executing..." );
        Counter counter = new Counter();
        
        //5 threads
        for (int i = 0; i < 5; i++) {
            Thread t = new Thread(counter);
            t.start();
        }
        
    }
    
    private  int performCount(int fixed) {
        return (fixed + count.incrementAndGet());
    }
}


Output:

main is executing...
Thread-1: result=7
Thread-2: result=8
Thread-3: result=9
Thread-4: result=10
Thread-5: result=11
Thread-1: result=16
Thread-3: result=13
Thread-2: result=12
Thread-4: result=15
Thread-5: result=14
Thread-1: result=20
Thread-5: result=19
Thread-2: result=21
Thread-4: result=17
Thread-3: result=18