Saturday, 21 January 2012

Synchronized method in Java with Example

Suppose a single thread wants to run a set of statements as a single unit (atomic action) and some other thread trying to disturb it by executing that same set of statements.Can you guess what will be the result??

See the example given below.Here one thread trying to print a statement [Hello] ,simultaneously another thread also trying to do the same thing.Will it work correctly??.Let us check.


public class Main {

public static void main(String[] args) {
MyResource resource = new MyResource();
MyThread t1 = new MyThread(resource);
MyThread t2 = new MyThread(resource);
t1.start();
t2.start();
}
}

class MyThread extends Thread {
MyResource resource;

public MyThread(MyResource resource) {
this.resource = resource;
}

public void run() {
try {
resource.display();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

class MyResource {

void display() throws InterruptedException {
//-------------Atomic Action Start----------
System.out.print("[");
Thread.sleep(1000);
System.out.print("HELLO");
Thread.sleep(1000);
System.out.println("]");
//------------Atomic Action End-----------
}
}

The expected result is
[HELLO]
[HELLO]
But the actual result is something  like
[[HELLOHELLO]

]

What is the reason for it.Both the threads t1 and t2 trying to execute the MyResource.display() method simultaneously.When one thread goes for sleep another thread executes this method and vice versa.
How can we solve it?.We can use the synchronized method or synchronized block in java to solve this problem.


package p1;

public class Main {

public static void main(String[] args) {
MyResource resource = new MyResource();
MyThread t1 = new MyThread(resource);
MyThread t2 = new MyThread(resource);
t1.start();
t2.start();
}
}

class MyThread extends Thread {
MyResource resource;

public MyThread(MyResource resource) {
this.resource = resource;
}

public void run() {
try {
resource.display();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

class MyResource {

synchronized void display() throws InterruptedException {
System.out.print("[");
Thread.sleep(1000);
System.out.print("HELLO");
Thread.sleep(1000);
System.out.println("]");
}
}

Here the expected and the actual result is

[HELLO]
[HELLO]

Consider another real-time example .

 void withdrawAmount(int amt)
{
    if(balance-amt>=min_balance)
  {
   balance=balance-amt;
   }
 }

Suppose Suresh and Harish ,two brothers have a joint account and both have individual ATM cards.If both are trying to withdraw an amount ,will it work correctly?.Consider a scenario ,both of them are trying to withdraw an amount 1000 simultaneously,current balance is 2000 and minimum required balance is 1000.

STEP1:Suresh checks condition(balance-1000>=min_bal) ---->True
STEP2:Harish checks condition(balance-1000>=min_bal) ---->True
STEP3:Suresh withdraws amount-------->balance=1000
STEP4:Harish withdraws amount-------->balance=0 (Invalid Transaction)

What is the problem ?. What is really  happened ?.We have to run the check for balance and withdraw as an atomic unit. i.e.

------------------Atomic Action Begins-----------------
STEP1:Suresh checks condition(balance-1000>=min_bal) ---->True
STEP2:Suresh withdraws amount-------->balance=1000
-----------------Atomic Action Begins------------------ 

-----------------Atomic Action Begins----------------
STEP3:Harish checks condition(balance-1000>=min_bal) ---->False
----------------Atomic Action Begins----------------- 

How can we implement it using synchronized in java.

 synchronized void withdrawAmount(int amt)
{
     if(balance-amt>=min_balance)
    {
      balance=balance-amt;
    }
}

All the statements within the synchronized method will act as a single atomic unit.

3 comments:

  1. Simple and Super....Very Userful...

    Thanks,
    Muthu Ram.M

    ReplyDelete
  2. Hi radha krishna garu can you please help me in my problem if possible
    /*My problem mainly deals with the synchronization in these example there is professor and two ta's(teaching assistant).Students will comes to the professor in a particular hours for questions on the subject but the professor allows only one person at a time so remaining must wait until the student comes out so professor can clarify the doubts only for 10 student in his office hours so if students are more than 10 they need to go the TA'S .
    In these example students are threads and prof and 2 ta's are sharedable resource.synchronization must be used to keep the threads(students )to wait
    Thanking you*/



    import java.io.*;
    import java.util.*;
    import java.util.Calender;

    public class Synchsema{

    public static boolean prof=false; /* default professor, ta1 & ta2 are
    public static boolean ta1=false; /* free and they are ready to recieve
    public static boolean ta2=false; /* students
    public static int student=0;

    public static void call() /* Checking the Professor(1st)
    { /* TA1(2nd), TA2(3rd) whether
    while(Synchsema.pprof==true) /* they are free or not
    {
    System.out.println(Thread.currentThread().getName( ) + " Professor is Busy");
    if(Synchsema.ta1==true)
    {
    if(Synchsema.ta2==true) /* if they are not free
    { /* student has to wait
    System.out.println(Thread.currentThread().getName( ) + " Ta1 & Ta2 is Busy"); /* for some time(sleep)
    System.out.println("Student has to wait some time");
    try
    {
    sleep(100);
    } catch (InterruptedException ex) {}
    }
    else /* if professor (busy) and Ta1
    { /* is busy check for Ta2
    Synchsema.student++; /* if Ta2 is free then Student allotted to Ta2.
    System.out.println("student " + Thread.currentThread().getName() + "alloted to Ta2");
    }
    } // if ta1
    else /* if professor (busy) and Ta1
    { /* is free then Student allotted to Ta1.
    Synchsema.student++;
    System.out.println("student " + Thread.currentThread().getName() + "alloted to Ta1");
    }
    }
    if (Synchsema.student >= 15) /* checking for 15 students
    { /* if students are over
    Synchsema.pprof = false; /* threads will be put as false.
    Synchsema.ta1 = false; /* and not used
    Synchsema.ta2 = false;
    }

    }
    public static void main(String args[]) /* main function for process creation
    { /* and thread creation
    Synchsema ss = new Synchsema();
    // ss.call();
    Processprof pprof = new Processprof();
    Processta1 ta1 = new Processta1();
    Processta2 ta2 = new Processta2();

    Calendar calendar = new GregorianCalendar();
    int hour = calendar.get(Calendar.HOUR);

    for(int i=1; i<=5; i++)
    {
    new Thread(pprof, "P: "+i).start();
    new Thread(ta1, "t1: "+i).start();
    new Thread(ta2, "t2: "+i).start();

    }
    if(hour==(hour+4)) /* checking for within working hours
    {
    pprof.Blocked();
    ta1.Blocked();
    ta2.Blocked();
    }
    }
    }

    class Processprof extends Thread /* Class for checking the condition whether the Professor
    { /* or TA1 or TA2 available
    public void run()
    {
    Synchsema.call();
    }
    }


    class Processta1 extends Thread /* Class for checking the condition whether the Professor
    { /* or TA1 or TA2 available
    public void run()
    {
    Synchsema.call();
    }
    }
    class Processta2 extends Thread /* Class for checking the condition whether the Professor
    { /* or TA1 or TA2 available
    public void run()
    {
    Synchsema.call();
    }
    }

    ReplyDelete