Java Threads

 

Thread States (Thread Life Cycle) 

The following diagram helps you visually understand the thread states and transitions between them:

thread-states
A thread can go through various states during its life. The Thread’s getState() method returns an enum constant that indicates current state of the thread, which falls in one of the following values:

- RUNNABLE

- BLOCKED

- WAITING

- TIMED_WAITING

- TERMINATED

These enum constants are defined in the Thread.State enum. Let me explain each state in details.

  • NEW: when a thread is created but has not executed (the start() method has not been invoked), it is in the new state.
 

  • RUNNABLE: when the start() method has been invoked, the thread enters the runnable state, and its run() method is executing. Note that the thread can come back to runnable state from another state (waiting, blocked), but it may not be picked immediately by the thread scheduler, hence the term “runnable”, not running.
 

  • BLOCKED: when a thread tries to acquire an intrinsic lock (not a lock in the java.util.concurrent package) that is currently held by another thread, it becomes blocked. When all other threads have relinquished the lock and the thread scheduler has allowed this thread to hold the lock, the thread becomes unblocked and enters the runnable state.
 

  • WAITING: a thread enters this state if it waits to be notified by another thread, which is the result of calling Object.wait() or Thread.join(). The thread also enters waiting state if it waits for a Lock or Condition in the java.util.concurrent package. When another thread calls Object‘s notify()/notifyAll() or Condition’s signal()/signalAll(), the thread comes back to the runnable state.
 

  • TIMED_WAITING: a thread enters this state if a method with timeout parameter is called: sleep()wait()join()Lock.tryLock() and Condition.await(). The thread exits this state if the timeout expires or the appropriate notification has been received.
 

  • TERMINATED: a thread enters terminated state when it has completed execution. The thread terminates for one of two reasons:
                + the run() method exits normally.
                + the run() method exits abruptly due to a uncaught exception occurs.

1. How to create a thread in Java

There are two ways for creating a thread in Java: by extending the Thread class; and by implementing the Runnable interface. Both are in the java.lang package so you don’t have to use import statement.

Then you put the code that needs to be executed in a separate thread inside the run() method which is overridden from the Thread/Runnable. And invoke the start() method on a Thread object to put the thread into running status (alive).

The following class, ThreadExample1, demonstrates the first way:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ThreadExample1 extends Thread {
 
    public void run() {
        System.out.println("My name is: " + getName());
    }
 
    public static void main(String[] args) {
        ThreadExample1 t1 = new ThreadExample1();
        t1.start();
 
        System.out.println("My name is: " + Thread.currentThread().getName());
    }
 
}

Let me explain to you how this code is working. You see that the ThreadExample1 class extends the Thread class and overrides the run() method. Inside the run() method, it simply prints a message that includes the name of the thread, which is returned from the getName() method of the Thread class.

And now let’s see the main() method that is invoked when the program starts. It creates an instance of the ThreadExample1 class and call its start() method to put the thread into running state. And the last line prints a message that includes the name of the main thread - every Java program is started from a thread called main. The static method currentThread() returns the Thread object associated with the current thread.

Run this program and you will see the output as follows:

1
2
My name is: Thread-0
My name is: main

You see, there are actually 2 threads:

Thread-0: is the name of the thread we created.

main: is the name of the main thread that starts the Java program.

The thread Thread-0 terminates as soon as its run() method runs to complete, and the thread main terminates after the main() method completes its execution.

One interesting point is that, if you run this program again for several times, you will see sometimes the thread Thread-0 runs first, sometimes the thread main runs first. This can be recognized by the order of thread names in the output changes randomly. That means there’s no guarantee of which thread runs first as they are both started concurrently. You should bear in mind this behavior with regard to multi-threading context.

Now, let’s see the second way that uses the Runnable interface. In the code below, the ThreadExample2 class implements the Runnable interface and override the run() method:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class ThreadExample2 implements Runnable {
 
    public void run() {
        System.out.println("My name is: " + Thread.currentThread().getName());
    }
 
    public static void main(String[] args) {
        Runnable task = new ThreadExample2();
        Thread t2 = new Thread(task);
        t2.start();
 
        System.out.println("My name is: " + Thread.currentThread().getName());
    }
 
}

As you can see, there’s a small difference as compared to the previous program: An object of type Runnable (the ThreadExample2 class) is created and passed to the constructor of a Thread object (t2). The Runnable object can be viewed as a task which is separated from the thread that executes the task.

The two programs behave the same. So what are the pros and cons of these two ways of creating a thread?

Here’s the answer:

- Extending the Thread class can be used for simple cases. It cannot be used if your class needs to extend another class because Java doesn’t allow multiple inheritances of class.

- Implementing the Runnable interface is more flexible as Java allows a class can both extend another class and implement one or more interfaces.

And remember that the thread terminates after its run() method returns. It is put into dead state and cannot be able to start again. You can never restart a dead thread.

You can also set name for a thread either via constructor of the Thread class or via the setter method setName(). For example:

1
2
3
4
Thread t1 = new Thread("First Thread");
 
Thread t2 = new Thread();
t2.setName("Second Thread");

 


MultiThreading.Java

-----------------------------

class ThreadEx extends Thread{
    public void run() {
        for(int idx = 0 ; idx <= 100 ; idx++) {
            System.out.println(Thread.currentThread().getName() + " : " + idx);
        }
    }
}
public class MultiThreading {

    public static void main(String[] args) {
        ThreadEx th0 = new ThreadEx();
        ThreadEx th1 = new ThreadEx();
        ThreadEx th2 = new ThreadEx();
       
        for(int idx = 0 ; idx <= 100 ; idx++) {
            System.out.println(Thread.currentThread().getName() + " : " + idx);
        }
       
        th0.start();
        th1.start();
        th2.start();
    }

}
 

--------------------------------------------------------------------------------------------------------------- 

MultiRunnableThis.Java

class ThreadRunThis implements Runnable{
    
    ThreadRunThis(){
        new Thread(this).start();
    }
    public void run() {
        for(int idx = 0 ; idx <= 500 ; idx++) {
            System.out.println(Thread.currentThread().getName() + " : " + idx);
        }
    }
}
public class MultiRunnableThis {

    public static void main(String[] args) {
        // no method start() exist for Runnable Interface, so is the error.
        // How to resolve this?
    
        ThreadRunThis th00 = new ThreadRunThis();
        ThreadRunThis th11 = new ThreadRunThis();
        ThreadRunThis th22 = new ThreadRunThis();
       
        for(int idx = 0 ; idx <= 50 ; idx++) {
            System.out.println(Thread.currentThread().getName() + " : " + idx);
        }
        // class ThreadRunThis doesn't have start method but Thread class does have.
       
    }

}

---------------------------------------------------------------------------------------

MultiRunnableThis2.Java

class ThreadRunThis2 implements Runnable{
    
    ThreadRunThis2(){
        new Thread(this).start();
    }
    public void run() {
        for(int idx = 0 ; idx <= 500 ; idx++) {
            System.out.println(Thread.currentThread().getName() + " : " + idx);
        }
    }
}
public class MultiRunnableThis2 {

    public static void main(String[] args) {
        // no method start() exist for Runnable Interface, so is the error.
        // How to resolve this?
    
        ThreadRunThis2 th00 = new ThreadRunThis2();
        ThreadRunThis2 th11 = new ThreadRunThis2();
        ThreadRunThis2 th22 = new ThreadRunThis2();
       
        for(int idx = 0 ; idx <= 50 ; idx++) {
            System.out.println(Thread.currentThread().getName() + " : " + idx);
        }
        // class ThreadRunThis doesn't have start method but Thread class does have.
       
       
    }

}
-----------------------------------------------------------------------------------------------------------

MultiThException.Java

class ThreadException extends Thread{
    public void run() {
        int[] arr = new int[10];
        arr[10] = 10;
    }
}
public class MultiThException {

    public static void main(String[] args) {
        ThreadException th0 = new ThreadException();
        ThreadException th1 = new ThreadException();
        ThreadException th2 = new ThreadException();
        th0.start();
        th1.start();
        th2.start();
        int[] arr = new int[10];
        arr[10] = 10;
       
    }

}
-----------------------------------------------------------------------------------------------------------------

 JoinMultiThreadin.Java

class ThreadExJoin extends Thread{
    public void run() {
        for(int idx = 0 ; idx <= 100 ; idx++) {
            System.out.println(Thread.currentThread().getName() + " : " + idx);
        }
    }
}
public class JoinMultiThreading {

    public static void main(String[] args) {
        ThreadExJoin th0 = new ThreadExJoin();
        ThreadExJoin th1 = new ThreadExJoin();
        ThreadExJoin th2 = new ThreadExJoin();
       
        for(int idx = 0 ; idx <= 50 ; idx++) {
            System.out.println(Thread.currentThread().getName() + " : " + idx);
        }
       
        th0.start();
        try {
            th0.join();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        th1.start();
        th2.start();
    }

}
-----------------------------------------------------------------------------------

 ThreadPriority.Java

// Priorities in Multithreading
// Use of getPriority() and setPriority() method



// Main class
public class ThreadPriority extends Thread {

    // Method 1
    // run() method for the thread that is called
    // as soon as start() is invoked for thread in main()
    public void run()
    {
        // Print statement
        System.out.println("Inside run method");
        for (int idx = 1; idx <= 200; idx++) {
            System.out.println(Thread.currentThread().getName() + " : " + idx);
        }
    }

    // Main driver method
    public static void main(String[] args)
    {
        // Creating random threads
        // with the help of above class
        ThreadPriority t1 = new ThreadPriority();
        ThreadPriority t2 = new ThreadPriority();
        ThreadPriority t3 = new ThreadPriority();

        // Thread 1
        // Display the priority of above thread
        // using getPriority() method
        System.out.println("t1 thread priority : "
                        + t1.getPriority());

        // Thread 1
        // Display the priority of above thread
        System.out.println("t2 thread priority : "
                        + t2.getPriority());

        // Thread 3
        System.out.println("t3 thread priority : "
                        + t3.getPriority());

        // Setting priorities of above threads by
        // passing integer arguments
        t1.setPriority(2);
        t2.setPriority(5);
        t3.setPriority(8);

        // t3.setPriority(21); will throw
        // IllegalArgumentException

        // 2
        System.out.println("t1 thread priority : "
                        + t1.getPriority());

        // 5
        System.out.println("t2 thread priority : "
                        + t2.getPriority());

        // 8
        System.out.println("t3 thread priority : "
                        + t3.getPriority());

        // Main thread

        // Displays the name of
        // currently executing Thread
        System.out.println(
            "Currently Executing Thread : "
            + Thread.currentThread().getName());

        System.out.println(
            "Main thread priority : "
            + Thread.currentThread().getPriority());

        // Main thread priority is set to 10
        Thread.currentThread().setPriority(10);

        System.out.println(
            "Main thread priority : "
            + Thread.currentThread().getPriority());
        t1.start();
        t2.start();
        t3.start();
    }
}
----------------------------------------------------------------------------------------------------------- 

 

Java Synchronization

Synchronization is a process of handling shared resource in harmony even with multiple thread requests. The main purpose of synchronization is to avoid thread interference. At times when more than one thread try to access a shared resource, we need to ensure that resource will be used by only one thread at a time. The process by which this is achieved is called synchronization. The synchronization keyword in java creates a block of code referred to as critical section.

General Syntax:

synchronized (object)
{
  //statement to be synchronized
}

Every Java object with a critical section of code gets a lock associated with the object. To enter critical section a thread need to obtain the corresponding object's lock.

Why we need Synchronization?

If we do not use synchronization, and let two or more threads access a shared resource at the same time, it will lead to distorted results.

Consider an example, Suppose we have two different threads T1 and T2, T1 starts execution and save certain values in a file temporary.txt which will be used to calculate some result when T1 returns. Meanwhile, T2 starts and before T1 returns, T2 change the values saved by T1 in the file temporary.txt (temporary.txt is the shared resource). Now obviously T1 will return wrong result.

To prevent such problems, synchronization was introduced. With synchronization in above case, once T1 starts using temporary.txt file, this file will be locked(LOCK mode), and no other thread will be able to access or modify it until T1 returns.

Using Synchronized Methods

Using Synchronized methods is a way to accomplish synchronization. But lets first see what happens when we do not use synchronization in our program.

Example with no Synchronization

In this example, we are not using synchronization and creating multiple threads that are accessing display method and produce the random output.

class First
{
  public void display(String msg)
  {
    System.out.print ("["+msg);
    try
    {
      Thread.sleep(1000);
    }
    catch(InterruptedException e)
    {
      e.printStackTrace();
    }
    System.out.println ("]");
  }
}

class Second extends Thread
{
  String msg;
  First fobj;
  Second (First fp,String str)
  {
    fobj = fp;
    msg = str;
    start();
  }
  public void run()
  {
    fobj.display(msg);
  }
}

public class Syncro
{
  public static void main (String[] args)
  {
    First fnew = new First();
    Second ss = new Second(fnew, "welcome");
    Second ss1= new Second(fnew,"new");
    Second ss2 = new Second(fnew, "programmer");
  }
}

[welcome [ new [ programmer] ] ]

In the above program, object fnew of class First is shared by all the three running threads(ss, ss1 and ss2) to call the shared method(void display). Hence the result is nonsynchronized and such situation is called Race condition..

Synchronized Keyword

To synchronize above program, we must synchronize access to the shared display() method, making it available to only one thread at a time. This is done by using keyword synchronized with display() method.

synchronized void display (String msg)

Example : implementation of synchronized method

class First
{
  synchronized public void display(String msg)
  {
    System.out.print ("["+msg);
    try
    {
      Thread.sleep(1000);
    }
    catch(InterruptedException e)
    {
      e.printStackTrace();
    }
    System.out.println ("]");
  }
}

class Second extends Thread
{
  String msg;
  First fobj;
  Second (First fp,String str)
  {
    fobj = fp;
    msg = str;
    start();
  }
  public void run()
  {
    fobj.display(msg);
  }
}

public class MyThread
{
  public static void main (String[] args)
  {
    First fnew = new First();
    Second ss = new Second(fnew, "welcome");
    Second ss1= new Second(fnew,"new");
    Second ss2 = new Second(fnew, "programmer");
  }
}

[welcome] [programmer] [new]

Using Synchronized block

If want to synchronize access to an object of a class or only a part of a method to be synchronized then we can use synchronized block for it. It is capable to make any part of the object and method synchronized.

Example

In this example, we are using synchronized block that will make the display method available for single thread at a time.

  
class First
{
  public void display(String msg)
  {
    System.out.print ("["+msg);
    try
    {
      Thread.sleep(1000);
    }
    catch(InterruptedException e)
    {
      e.printStackTrace();
    }
    System.out.println ("]");
  }
}

class Second extends Thread
{
  String msg;
  First fobj;
  Second (First fp,String str)
  {
    fobj = fp;
    msg = str;
    start();
  }
  public void run()
  {
    synchronized(fobj)      //Synchronized block
    {
      fobj.display(msg);
    }
  }
}

public class MyThread
{
  public static void main (String[] args)
  {
    First fnew = new First();
    Second ss = new Second(fnew, "welcome");
    Second ss1= new Second (fnew,"new");
    Second ss2 = new Second(fnew, "programmer");
  }
}
  

[welcome] [new] [programmer]

Because of synchronized block this program gives the expected output.

Difference between synchronized keyword and synchronized block

When we use synchronized keyword with a method, it acquires a lock in the object for the whole method. It means that no other thread can use any synchronized method until the current thread, which has invoked it's synchronized method, has finished its execution.

synchronized block acquires a lock in the object only between parentheses after the synchronized keyword. This means that no other thread can acquire a lock on the locked object until the synchronized block exits. But other threads can access the rest of the code of the method.

Which is more preferred - Synchronized method or Synchronized block?

In Java, synchronized keyword causes a performance cost. A synchronized method in Java is very slow and can degrade performance. So we must use synchronization keyword in java when it is necessary else, we should use Java synchronized block that is used for synchronizing critical section only.

 

 

 

 MutuallyExclusiveBlock.Java

package sync;

class Table {
    public void display(int num) {
        synchronized (this) {
            System.out.println("Got the CPU - " +Thread.currentThread().getName());
            for (int idx = 1; idx <= 100; idx++) {
                System.out.println(num * idx);
            }
        }
    }
}

class Thread1 extends Thread {

    private Table t;

    public Thread1(Table t) {
        this.t = t;
    }

    public void run() {
        System.out.println("Ready Queue, Runnable State - " +Thread.currentThread().getName());
        t.display(5);
    }
}

class Thread2 extends Thread {

    private Table t;

    public Thread2(Table t) {
        this.t = t;
    }

    public void run() {
        System.out.println("Ready Queue, Runnable State - " + Thread.currentThread().getName());
        t.display(10);
    }
}

// Critical section problem - handled using synchronized Block
public class MutuallyExclusiveBlock {

    public static void main(String[] args) {
        Table t = new Table();
        Thread1 th1 = new Thread1(t);
        Thread2 th2 = new Thread2(t);
        th1.start();
        th2.start();

    }

}
-------------------------------------------------------------------------------------------------------------

 MutuallyExclusiveWrong.Java

class Table1 {

    public synchronized void display(int num) {
        for (int idx = 1; idx <= 200; idx++) {
            System.out.println(num * idx);
        }
    }
}

class Thread11 extends Thread {

    public void run() {
        Table1 t = new Table1();
        System.out.println(Thread.currentThread().getName());
        t.display(5);
    }
}

class Thread21 extends Thread {
    
    public void run() {
        Table1 t = new Table1();
        System.out.println(Thread.currentThread().getName());
        t.display(10);
    }
}

// Critical section problem - handled using synchronized keyword
public class MutuallyExclusiveWrong {

    public static void main(String[] args) {
       
        Thread11 th1 = new Thread11();
        Thread21 th2 = new Thread21();
        th1.start();
        th2.start();

    }

}
-------------------------------------------------------------------------------------------------------------------

MutuallyExclusive .Java

class Table {

    public static void display(int num) {
        synchronized(Table.class) {
            for (int idx = 1; idx <= 200; idx++) {
                System.out.println("Got the CPU - " + Thread.currentThread().getName() + ":" + num * idx);
            }
        }
    }
}

class Thread1 extends Thread {

    public void run() {
        System.out.println("Ready Queue, Runnable State - " + Thread.currentThread().getName());
        Table.display(5);
    }
}

class Thread2 extends Thread {

    public void run() {
        System.out.println(Thread.currentThread().getName());
        Table.display(10);
    }
}

// MutuallyExclusive using lock on the class, not on the object
public class MutuallyExclusive {

    public static void main(String[] args) {
        Thread1 th1 = new Thread1();
        Thread2 th2 = new Thread2();
        th1.start();
        th2.start();

    }

}

Java Thread Priorities

Priority of a thread describes how early it gets execution and selected by the thread scheduler. In Java, when we create a thread, always a priority is assigned to it. In a Multithreading environment, the processor assigns a priority to a thread scheduler. The priority is given by the JVM or by the programmer itself explicitly. The range of the priority is between 1 to 10 and there are three constant variables which are static and used to fetch priority of a Thread. They are as following:

1. public static int MIN_PRIORITY

It holds the minimum priority that can be given to a thread. The value for this is 1.

2. public static int NORM_PRIORITY

It is the default priority that is given to a thread if it is not defined. The value for this is 0.

3. public static int MAX_PRIORITY

It is the maximum priority that can be given to a thread. The value for this is 10.

Get and Set methods in Thread priority

1. public final intgetPriority()

In Java, getPriority() method is in java.lang.Thread package. it is used to get the priority of a thread.

2. public final void setPriority(intnewPriority)

In Java setPriority(intnewPriority) method is in java.lang.Thread package. It is used to set the priority of a thread. The setPriority() method throws IllegalArgumentException if the value of new priority is above minimum and maximum limit.

Example: Fetch Thread Priority

If we don’t set thread priority of a thread then by default it is set by the JVM. In this example, we are getting thread’s default priority by using the getPriority() method.

    
class MyThread extends Thread 
{ 
	public void run() 
	{ 
		System.out.println("Thread Running..."); 
	} 

	public static void main(String[]args) 
	{ 
		MyThread p1 = new MyThread(); 
		MyThread p2 = new MyThread(); 
		MyThread p3 = new MyThread(); 
		p1.start();
		System.out.println("P1 thread priority : " + p1.getPriority()); 
		System.out.println("P2 thread priority : " + p2.getPriority());  
		System.out.println("P3 thread priority : " + p3.getPriority()); 
		
	} 
}
    

P1 thread priority : 5 Thread Running... P2 thread priority : 5 P3 thread priority : 5

Example: Thread Constants

We can fetch priority of a thread by using some predefined constants provided by the Thread class. these constants returns the max, min and normal priority of a thread.

	
class MyThread extends Thread 
{ 
	public void run() 
	{ 
		System.out.println("Thread Running..."); 
	} 

	public static void main(String[]args) 
	{ 
		MyThread p1 = new MyThread(); 
		p1.start();
		System.out.println("max thread priority : " + p1.MAX_PRIORITY); 
		System.out.println("min thread priority : " + p1.MIN_PRIORITY);  
		System.out.println("normal thread priority : " + p1.NORM_PRIORITY); 
		
	} 
}
	

Thread Running... max thread priority : 10 min thread priority : 1 normal thread priority : 5

Example : Set Priority

To set priority of a thread, setPriority() method of thread class is used. It takes an integer argument that must be between 1 and 10. see the below example.

	
class MyThread extends Thread 
{ 
	public void run() 
	{ 
		System.out.println("Thread Running..."); 
	} 

	public static void main(String[]args) 
	{ 
		MyThread p1 = new MyThread();
		// Starting thread
		p1.start();
		// Setting priority
		p1.setPriority(2);
		// Getting priority
		int p = p1.getPriority();
		
		System.out.println("thread priority : " + p);  
		
	} 
}
	

thread priority : 2 Thread Running...

Example:

In this example, we are setting priority of two thread and running them to see the effect of thread priority. Does setting higher priority thread get CPU first. See the below example.

	
class MyThread extends Thread 
{ 
	public void run() 
	{ 
		System.out.println("Thread Running... "+Thread.currentThread().getName()); 
	} 

	public static void main(String[]args) 
	{ 
		MyThread p1 = new MyThread();
		MyThread p2 = new MyThread();
		// Starting thread
		p1.start();
		p2.start();
		// Setting priority
		p1.setPriority(2);
		// Getting -priority
		p2.setPriority(1);
		int p = p1.getPriority();
		int p22 = p2.getPriority();
		
		System.out.println("first thread priority : " + p);  
		System.out.println("second thread priority : " + p22);
		
	} 
}
	

Thread Running... Thread-0 first thread priority : 5 second thread priority : 1 Thread Running... Thread-1

Note: Thread priorities cannot guarantee that a higher priority thread will always be executed first than the lower priority thread. The selection of the threads for execution depends upon the thread scheduler which is platform dependent.

Comments

Popular posts from this blog

Advanced Java - JDBC

Core Java BCA3