The Java Multi Threading - advance concepts and synchronized


Learn java multi threading concepts, learn about synchronization and creating multiple threads and using them. How to manage the thread timing and how to set priority.

This is second part of the Java Threading series, if you have not read the basic and you are new to the concept we suggest you read the post on The Basics of Java Threading and then come back to read on.

This is the second part of the Java Threading or we should say now multi threading. However there was no example of creating and running multiple threads, but in this post we are going to show you how you can create multiple threads, how you can use them and how you can define different priorities, how you can work them together and probably how you can sync them and avoid deadlocks in thread. So, let us start now.

Multiple Threads and their Priority

Java is as we told you already, a thread oriented language, and this model helps to keep it light and fast on runtime. However the main method acts as a thread itself but this parent thread has child thread. Making child thread means Java support more than one thread in the program. You can achieve it in two possible ways, what way you choose is dependent on your needs however both in terms of performance are same. First one is as below, in this case I am creating three thread for one object of ThreadingDemo class. First try to understand the program and later we'll explain how it is working.


public class ThreadingDemo implements Runnable{
    private Thread th1,th2,th3;
    public void startThread(){
        th1 = new Thread(this,"th1");
        th2 = new Thread(this,"th2");
        th3 = new Thread(this,"th3");
        th1.setPriority(Thread.MIN_PRIORITY);
        th2.setPriority(Thread.NORM_PRIORITY);
        th3.setPriority(Thread.MAX_PRIORITY);
        th1.start();
        th2.start();
        th3.start();
    }
    
    public void run(){
        for(int i=0; i<5; i++){
            try{
                System.out.println("Current Thread is: "+Thread.currentThread()+" with priority: "+Thread.currentThread().getPriority()+" and count value is "+i);
                Thread.sleep(1000);
                
            }
            catch(InterruptedException ie){
                System.out.println(ie);
            }
        }
    }
    
    public static void main(String[] args){
        ThreadingDemo td = new ThreadingDemo();
        td.startThread();
    }
}

Just so you could see the difference properly I am going to color the output:
Current Thread is: Thread[th2,5,main] with priority: 5 and count value is 0
Current Thread is: Thread[th1,1,main] with priority: 1 and count value is 0
Current Thread is: Thread[th3,10,main] with priority: 10 and count value is 0
Current Thread is: Thread[th2,5,main] with priority: 5 and count value is 1
Current Thread is: Thread[th1,1,main] with priority: 1 and count value is 1
Current Thread is: Thread[th3,10,main] with priority: 10 and count value is 1
Current Thread is: Thread[th2,5,main] with priority: 5 and count value is 2
Current Thread is: Thread[th1,1,main] with priority: 1 and count value is 2
Current Thread is: Thread[th3,10,main] with priority: 10 and count value is 2
Current Thread is: Thread[th2,5,main] with priority: 5 and count value is 3
Current Thread is: Thread[th1,1,main] with priority: 1 and count value is 3
Current Thread is: Thread[th3,10,main] with priority: 10 and count value is 3
Current Thread is: Thread[th1,1,main] with priority: 1 and count value is 4
Current Thread is: Thread[th3,10,main] with priority: 10 and count value is 4
Current Thread is: Thread[th2,5,main] with priority: 5 and count value is 4

The working of program is just the way you create a normal thread, but instead we have created three thread object and we have given them name, th1, th2 and th3. The priority of the thread is can be defined from the range of 1 to 10 where one being the minimum and 10 being maximum. You can define the priority using the method setPriority(). There are three predefined priority constants which can also be used to serve the purpose. These are static final so you can not redefine them and you will have to access them using class name. these are:
Thread.MIN_PRIORITY having integer value 1,
Thread.NORM_PRIORITY having integer value 5 and
Thread.MAX_PRIORITY having integer value 10

The thread priority is a parameter defining which thread to give preference over other, however it is completely dependent on the JVM rather than your CPU.

So let us come back to our program and output. The program creates and object and invoke startThread() method which in turn create three threads and execute them according to the code written in run() method.

The output as you can see take some effect from the priority but most of the time it remains the same to what it took start at. There could be another version of this above program with very slight difference in which the Thread object is one but the threads are three by the virtue of three ThreadingDemo objects. Please see this variation in the program below.


public class ThreadingDemo implements Runnable{
    private Thread th;
    public void startThread(String name,int priority){
        th = new Thread(this,name);
        th.setPriority(priority);
        th.start();
    }
    
    public void run(){
        for(int i=0; i<5; i++){
            try{
                System.out.println("Current Thread is: "+Thread.currentThread()+" with priority: "+Thread.currentThread().getPriority()+" and count value is"+i);
                Thread.sleep(1000);
                
            }
            catch(InterruptedException ie){
                System.out.println(ie);
            }
        }
    }
    
    public static void main(String[] args){
        ThreadingDemo td1 = new ThreadingDemo();
        ThreadingDemo td2 = new ThreadingDemo();
        ThreadingDemo td3 = new ThreadingDemo();
        td1.startThread("Thread-A",Thread.MIN_PRIORITY);
        td2.startThread("Thread-B",Thread.NORM_PRIORITY);
        td3.startThread("Thread-C",Thread.MAX_PRIORITY);
    }
}

the output comes as follows:
Current Thread is: Thread[Thread-A,1,main] with priority: 1 and count value is 0
Current Thread is: Thread[Thread-C,10,main] with priority: 10 and count value is 0
Current Thread is: Thread[Thread-B,5,main] with priority: 5 and count value is 0
Current Thread is: Thread[Thread-A,1,main] with priority: 1 and count value is 1
Current Thread is: Thread[Thread-C,10,main] with priority: 10 and count value is 1
Current Thread is: Thread[Thread-B,5,main] with priority: 5 and count value is 1
Current Thread is: Thread[Thread-A,1,main] with priority: 1 and count value is 2
Current Thread is: Thread[Thread-C,10,main] with priority: 10 and count value is 2
Current Thread is: Thread[Thread-B,5,main] with priority: 5 and count value is 2
Current Thread is: Thread[Thread-A,1,main] with priority: 1 and count value is 3
Current Thread is: Thread[Thread-B,5,main] with priority: 5 and count value is 3
Current Thread is: Thread[Thread-C,10,main] with priority: 10 and count value is 3
Current Thread is: Thread[Thread-A,1,main] with priority: 1 and count value is 4
Current Thread is: Thread[Thread-C,10,main] with priority: 10 and count value is 4
Current Thread is: Thread[Thread-B,5,main] with priority: 5 and count value is 4

So, Now we hope you understand the creation and working of multiple thread and their priority. So let us now make understanding about the synchronization between multiple threads, and for this Java provide special feature of synchronization. Before we move on to synchronization we would like to introduce you with a problem, which will tell you why we need synchronization.

John and Kenny are two best friends and they had a common account in bank. At any time they could withdraw the amount. One day John went to withdraw $500 from the account where the total balance in the account was $600. At the same time Kenny went to withdraw. Now while the John was checking balance it showed him $500 and then Kenny withdraw the $400 so left were $200. After checking balance John tried to withdraw but he got an error telling that balance was insufficient.

So, did you identified the problem, which happened with John? Well when John was accessing the account there should have been no access to Kenny until John finishes his transaction. This problem points towards the Shared resources.

So, synchronized keyword and concept provides you with the lock on the resources. That means when a thread is accessing any resource and it goes to sleep for some time, no one else can access that resource unless first thread completes the transaction. following example will show you the problem and solution also.


import java.util.*;

class user extends Thread {

    static int amnt = 600;
    int wdrw, deposit;
    static user user = new user();

    public static void main(String[] args) {
        Thread Jhon = new Thread(new Runnable(){
            public void run() {
                //System.out.println(user.withdraw());
                System.out.println(user.deposit());
            }
        });
        Thread Kenny = new Thread(new Runnable(){
            public void run() {
                System.out.println(user.withdraw());
                //System.out.println(user.deposit());
            }
        });
        Jhon.start();
        Kenny.start();
    }

    public synchronized int withdraw() {
        System.out.println("Enter the amount to withdraw");
        Scanner sc = new Scanner(System.in);
        int wdrw = sc.nextInt();
        System.out.println(Thread.currentThread());
        if (wdrw <= amnt) {
            amnt = amnt - wdrw;
            return amnt;
        } else {
            System.out.println("Enter less amount");
            return wdrw;
        }

    }

    public synchronized int deposit() {
        System.out.println("Enter the amount to deposit");
        Scanner sc = new Scanner(System.in);
        int deposit = sc.nextInt();
        amnt = amnt + deposit;
        return amnt;
    }
}

So let us explain it to you how this program works, there are two threads named created for John and Kenny and both are doing operation on the account. So we created two method withdraw and deposit. If you have noticed there is synchronized keyword used, this will take care that if one object of thread is accessing the method other could not take control of that method. This is how the Monitors work for the concurrency.

try to run this system with the various input it asks, and you will find that at anytime only one of them would be able to perform the operation, not both. Here is a suggestion. try to make a simple program which uses the synchronized method or block and see if it lets another program access in any way when one is working.

Note: we have left comments there so that you could try to remove the comments and try that code too.