in Core Java

Thread Safety and Code synchronization in Java

Thread Safety and Code Synchronization in Java

With the advent of Multi core processors, The applications certainly need to be good at Multithreading to utilize the resources. But good care should be taken when designing multithreaded applications where Thread safety should be on top of the agenda for the Designer.

Let us see why thread safety is of paramount importance in Multithreaded applications.

Thread Safety  - An example

Consider an example – A couple who have a Joint account where both have their ATM cards. They come to different ATMs and try to withdraw some amount at the same time. Now the total balance in the account is 500, Wife tries to withdraw 450 and husband tried to withdraw 100. Both of them were shown the balance as 500. When trying to with draw, the two threads assigned for the transactions try to withdraw the amount. But only one succeeds and other fails.  This creates a confusion among the users. This happens because there is no restriction that only one thread is allowed to work on the data at a given time.

Thread Safety – Need for Code synchronization

Let us consider another example where we have a travel website happybus.com through which you can book your bus tickets.

Now there are only three seats left and two people are trying to book the tickets at the same time. Only one will be able to proceed and other will fail.

If you consider in both the cases, the trouble arises when different threads try to work on the same data at same time.

To avoid this problem, the code synchronization should be implemented which restricts multiple threads to work on the same code at the same time.

Now, Let us see a simple demo of code without thread safety.  Given below is the code which demonstrates the Bus reservation example without Thread Safety.

Thread Safety – Code without synchronization – example

BusReservation.java
public class BusReservation implements Runnable{
private int totalSeatsAvailable=2;public void run() {
//BusReservation br = new BusReservation();
PassengerThread pt = (PassengerThread) Thread.currentThread();
boolean ticketsBooked = this.bookTickets(pt.getSeatsNeeded(), pt.getName());
if(ticketsBooked==true){
System.out.println(“CONGRATS”+Thread.currentThread().getName()+” .. The number of seats requested(“+pt.getSeatsNeeded()+”) are BOOKED”);
}else{
System.out.println(“Sorry Mr.”+Thread.currentThread().getName()+” .. The number of seats requested(“+pt.getSeatsNeeded()+”) are not available”);
}
}public boolean bookTickets(int seats, String name){
System.out.println(“Welcome to HappyBus “+Thread.currentThread().getName()+” Number of Tickets Available are:”+this.getTotalSeatsAvailable());if (seats>this.getTotalSeatsAvailable()) {
return false;
} else {totalSeatsAvailable = totalSeatsAvailable-seats;return true;
}
}

private int getTotalSeatsAvailable() {
return totalSeatsAvailable;
}

}

PassengerThread.java

//This represent a Passenger. The reasons for extending the Thread class is that this should carry the data of number of seats.
public class PassengerThread extends Thread{

private int seatsNeeded;

public PassengerThread(int seats, Runnable target, String name) {
super(target,name);
this.seatsNeeded = seats;
}

public int getSeatsNeeded() {
return seatsNeeded;
}

}

ThreadSafetyDemo.java

public class ThreadSafetyDemo{

public static void main(String[] args){
BusReservation br = new BusReservation();
PassengerThread pt1 = new PassengerThread(2,br,”SAM”);
PassengerThread pt2 = new PassengerThread(2, br, “Jack”);
pt1.start();
pt2.start();
}
}

Output:
Welcome to HappyBus SAM Number of Tickets Available are:2
Welcome to HappyBus Jack Number of Tickets Available are:2
CONGRATSSAM .. The number of seats requested(2)  are BOOKED
Sorry Mr.Jack .. The number of seats requested(2)  are not available

In the above output, you can see that both user have got the number of tickets available as 2. But when the second user thread tried, the sorry message came out as the first user thread was able to successfully block the ticket.

This kind of code behavior creates confusion in users and can have adverse effects in the data consistency. To avoid these situation it is important to restrict the threads to act in queue. Code synchronization helps to restrict the multiple thread access for a particular part of the code.

Code Synchronization:

Code Synchronization helps in preventing threads working on the same code at the same time. The synchronization works based on the locking concept.

  • Threads that work on the synchronized code should acquire the lock of the object or class file respectively.
  • Please remember and important point that there is only one lock per object or loaded class file.
  • Synchronization can only be applied for method or block of code. But not for classes or variables.

Syntax:

public synchronize void method(){ }

public static synchronize void method{…}

synchronize(this){…}

Threads and Object locks  – Behaviour

Now let me explain in detail how Objects locks work and avoid different threads to stop executing the same code.,

Threads and Object Locking example
Threads and Object locking with example

I have four objects here . Obj1, Obj2, Obj 3, Obj4. Each has different methods and the methods marked with s are synchronized.

Now consider we have two threads, Thread 1 and Thread 2 Both trying to access different methods on ObJ1 Which in turn connect to different method of other objects.

Consider that both threads are started together and let us see the Thread one execution.

When T1 come to M1 in Object 1, It sees that this method is synchronized and it acquires the lock of Obj1.

From Obj1 M1 method, the calls are going to other methods and in this process, the thread acquires locks of different threads. The  locks are given in the lock board of thread 1.

On the other side, the Thread 2 trying to access M2 on Obj1 is waiting for the lock of Obj1 to be released by thread 1. Even though both are executing different methods, you should remember that because there is only one lock per object, there no other go for Thread 2 but to wait till lock is released by thread 1.

This is most important concept you have to remember.

To give a good real life example to match thread locking, it is like obtaining locks for a hotel room by a customer.  If another customer want to occupy the same room, he needs to wait for the room lock to be returned.

Object Locks - Example
Object locks are like lock of a Hotel room. Only a person who has the lock has access. Other should wait.

Why there is only a single lock per object?

I think a question might be popping in your mind that why they have allowed only one lock per object. What is the issue even if threads are accessing different methods?

Here is a scenario which answers your question.

Why only single lock per object?
There is a good chance that different methods might change the same data and if multiple locks are present, different threads will get the ability to change the data at same time.

I have two methods – Book tickets and cancel tickets. Both of them work on the same data – Total tickets.

Now when two threads at the same time work on these two methods,  they will be able to work on the same data at the same time.  So, considering the data manipulation, the locks were implemented on the object level instead of method level.

Now let us see how the bus reservation work when we put synchronization in place.

Code Synchronization with example:

Given below is the BusReservation class. I have just added synchronized keyword to the bookTickets method. Other classes remain same.
public class BusReservation implements Runnable{
private int totalSeatsAvailable=2;

public void run() {
//BusReservation br = new BusReservation();
PassengerThread pt = (PassengerThread) Thread.currentThread();
boolean ticketsBooked = this.bookTickets(pt.getSeatsNeeded(), pt.getName());
if(ticketsBooked==true){
System.out.println(“CONGRATS”+Thread.currentThread().getName()+” .. The number of seats requested(“+pt.getSeatsNeeded()+”)  are BOOKED”);
}else{
System.out.println(“Sorry Mr.”+Thread.currentThread().getName()+” .. The number of seats requested(“+pt.getSeatsNeeded()+”)  are not available”);
}
}

public  synchronized boolean bookTickets(int seats, String name){
System.out.println(“Welcome to HappyBus “+Thread.currentThread().getName()+” Number of Tickets Available are:”+this.getTotalSeatsAvailable());

if (seats>this.getTotalSeatsAvailable()) {
return false;
} else {

totalSeatsAvailable = totalSeatsAvailable-seats;

return true;
}
}

private int getTotalSeatsAvailable() {
return totalSeatsAvailable;
}

}

Output:
Welcome to HappyBus SAM Number of Tickets Available are:2
Welcome to HappyBus Jack Number of Tickets Available are:0
CONGRATSSAM .. The number of seats requested(2) are BOOKED
Sorry Mr.Jack .. The number of seats requested(2) are not available

You can see that Jack has got the message that there are no seats available. The code synchronization has restricted both the threads to enter bookTickets Method as the same time which avoids the number of tickets available to be displayed for both of them at the same time.

References:
Download the PPT of Thread Safety
Download the example code

Srinivas Reddy

Srinivas Reddy

An IT - Specialist with loads of experience in Java, J2ee platforms and loves to share his experience on technology with You...

More Posts - Website

Follow Me:
TwitterFacebook

Srinivas Reddy
Written By:

An IT - Specialist with loads of experience in Java, J2ee platforms and loves to share his experience on technology with You...