Before we explain synchronization in Java, we must briefly revisit the concept of multithreading. The multithreading feature of Java allows the simultaneous execution of two or more parts of a program for maximum CPU utilisation. Each part of such a program is a thread, and threads are lightweight processes within a process.
Now, multiple threads of a program may try to access the same resources and produce inaccurate results. So, there must be some synchronization to ensure that only one thread has access to resources at a given point in time.
This guide on what is synchronization in Java will explore the concept of synchronization in detail with examples.
What is synchronization in Java?
Java synchronization is the ability to control the access of multiple threads to a shared resource. It is useful when multi-threaded Java programs attempt to access the same resource and produce erroneous outcomes. Using the Java synchronization feature, only a single thread can get to the resource at a given time point.
Java provides a way to synchronize the task of threads using synchronized blocks that synchronize on the same object and can have only one thread executing inside them at a time. These blocks are marked with the synchronized keyword, blocking any other thread attempting to get into the synchronized block until the thread already inside the block ends its execution and leaves the block.
The syntax for Writing a Synchronized Block
The general syntax for writing a synchronized block in Java is as follows:
synchronized( lockObject )
{
// synchronized statements
}
In the above syntax, lockObject refers to an object whose lock is related to the synchronized elements. Now, that brings us to the lock concept in Java.
Locks in Java
Synchronization in Java is built around the lock or monitor. Every object has an associated lock. Ideally, a thread that requires access to the fields of an object must first obtain the object’s lock. The lock is a more sophisticated and flexible thread synchronization mechanism than the synchronization block. It is defined inside the java.util.concurrent.lock package containing extensive lock implementations.
Learn Online software development courses from the World’s top Universities. Earn Executive PG Programs, Advanced Certificate Programs, or Masters Programs to fast-track your career.
Java Synchronized Method
The purpose of a Java synchronized method is to lock objects for shared resources. Thus, when threads invoke a synchronized method, the method automatically gets the lock for that object and releases it once the thread executes its job.
Here’s an example of a Java synchronized method:
//example of java synchronized method
class Table{
synchronized void printTable(int n){//synchronized method
for(int i=1;i<=5;i++){
System.out.println(n*i);
try{
Thread.sleep(400);
}catch(Exception e){System.out.println(e);}
}
}
}
class MyThread1 extends Thread{
Table t;
MyThread1(Table t){
this.t=t;
}
public void run(){
t.printTable(5);
}
}
class MyThread2 extends Thread{
Table t;
MyThread2(Table t){
this.t=t;
}
public void run(){
t.printTable(100);
}
}
public class TestSynchronization2{
public static void main(String args[]){
Table obj = new Table();//only one object
MyThread1 t1=new MyThread1(obj);
MyThread2 t2=new MyThread2(obj);
t1.start();
t2.start();
}
}
Output:
5
10
15
20
25
100
200
300
400
500
What happens without synchronization?
Now, let’s look at the previous program without synchronization (note the absence of the synchronized keyword).
class Table{
void printTable(int n){//method not synchronized
for(int i=1;i<=5;i++){
System.out.println(n*i);
try{
Thread.sleep(400);
}catch(Exception e){System.out.println(e);}
}
}
}
class MyThread1 extends Thread{
Table t;
MyThread1(Table t){
this.t=t;
}
public void run(){
t.printTable(5);
}
}
class MyThread2 extends Thread{
Table t;
MyThread2(Table t){
this.t=t;
}
public void run(){
t.printTable(100);
}
}
class TestSynchronization1{
public static void main(String args[]){
Table obj = new Table();//only one object
MyThread1 t1=new MyThread1(obj);
MyThread2 t2=new MyThread2(obj);
t1.start();
t2.start();
}
}
Output:
5
100
10
200
15
300
20
400
25
500
As you can see, the output is inconsistent without synchronization.
Explore our Popular Software Engineering Courses
Types of Synchronization in Java
To answer what is thread synchronization in Java, we have two types of synchronization available: thread synchronization and process synchronization.
Let’s understand what each means.
Thread synchronization: When multiple threads try to access a shared resource, we must ensure that the resource is used by only one thread at a time. Thread synchronization is the process of allowing only one thread to use the shared resource when multiple threads are trying to use the resource simultaneously.
Process synchronization: It refers to the simultaneous execution of multiple processes to reach a state where the processes commit to an appropriate order of execution. Process synchronization is required when two or more processes cooperate, and the execution of one process affects the other. Thus, process synchronization eliminates the possibility of inaccurate outputs and guarantees the proper execution order.
Methods of Synchronization in Java
Broadly, there are four methods of synchronization in Java:
- Synchronized static methods
- Synchronized instance methods
- Synchronized block inside static methods
- Synchronized block inside instance methods
Let’s look at each method of Java synchronization in more detail.
Synchronized static methods
Here, we use the synchronized keyword to mark the static methods in Java. Here’s an example of a Java synchronized static method:
public static MyStaticCounter {
private static int count = 0;
public static synchronized void increment(int value) {
count += value;
}
}
Synchronized instance methods
When using a synchronized block with instance methods, each object has its synchronized method. Each object can have only one thread that can execute inside a method. If there are multiple objects, a single thread can execute for each object inside the block.
public class MyCounter {
private int count = 0;
public synchronized void increment(int value) {
this.count += value;
}
public synchronized void decrement(int value) {
this.count -= value;
}
}
Synchronized block inside static methods
Below is an example where we use a synchronized block inside a static method:
public class MyClass {
public static void print(String message) {
synchronized(MyClass.class) {
log.writeln(message);
}
}
}
Synchronized block inside instance methods
Instead of synchronizing the entire method, we can use synchronized on a specific block within the method. Below is an example of a synchronized block of code inside an unsynchronized method:
public void increment(int value) {
synchronized(this) {
this.count += value;
}
}
Need for Synchronization in Java
Now that you know what is synchronization in Java, you might be wondering why we use it in the first place.
The Java synchronized keyword provides functionalities essential for concurrent programming. Here’s how synchronization in Java helps:
- Java synchronization provides the locking feature to eliminate any race condition among threads and ensure mutually exclusive access to the shared resource.
- The Java synchronized locking provides both the locking and unlocking features. So, a thread needs to acquire the lock before entering a synchronized method or block.
- The synchronized keyword prevents the reordering of program statements by the compiler.
Conclusion
Summing up, synchronization in Java makes sure that only one thread can access the shared resource at a time. We can make a block or method synchronized using the Java synchronized keyword. When a thread wants to get inside a synchronized block, it must acquire a lock, and after leaving the block, the thread releases the lock. We can use the synchronized keyword either with methods or inside the block of a method.
Wondering where to learn Java?
upGrad’s Job-linked PG Certification in Software Engineering is what you’re looking for!
Specially designed for fresh graduates and final years, upGrad’s Job-linked PG Certification in Software Engineering is perfect for those who want to learn to program and get placed in entry-level software roles. This 5-month online program will teach top software skills like Java, JavaScript, HTML5, DSA, AWS, MERN, and more!
Q: Why do we use synchronized in Java?
A: The synchronized keyword in Java ensures that only one thread can access the shared resources at a time. It is useful when multi-threaded Java programs attempt to access the same resource and produce inaccurate outcomes.
Q: How is synchronization implemented in Java?
A: Java implements synchronization using the concept of monitors with only one thread owning a monitor at a given time. When a thread acquires a lock, it gets access to the monitor, and all other threads attempting to get into the locked monitor remain blocked until the first thread leaves the monitor.
Q: What is a deadlock in Java?
A: Java deadlock occurs when a thread is waiting for an object lock, but another thread acquires it, and the second thread is waiting for an object lock acquired by the first one. Hence, both the threads wait for each other to release the lock, resulting in a deadlock.