Synchronization is the process which ensures that only one thread can access the resource at a time. This means it is the capability to control the access of multiple threads to any shared resources.
Why synchronization?
To prevent consistency problem
To prevent thread interference
How to achieve synchronization in java?
Synchronized method()
A method level lock.
synchronized void print(int n){
for(int i=1;i<=5;i++){
System.out.println(n);
}
}
}
Synchronized block
A block level lock. We can lock specific number of lines in a block of code.
public class Table {
public void printTable(int n) {
for (int i = 1; i <= 5; i++) {
synchronized (this) {
System.out.println(n * i + " Thread name " + Thread.currentThread().getName());
try {
Thread.sleep(400);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public class MyThread1 extends Thread {
Table table;
MyThread1(Table table) {
this.table = table;
}
public void run() {
table.printTable(5);
}
}
public class MyThread2 extends Thread {
Table table;
MyThread2(Table table) {
this.table = table;
}
public void run() {
table.printTable(100);
}
}
public class Main {
public static void main(String[] args) {
Table singleObject = new Table(); // same object
MyThread1 thread1 = new MyThread1(singleObject);
MyThread2 thread2 = new MyThread2(singleObject);
thread1.start();
thread2.start();
}
}
//ouput, thread1 release lock after it completes execution
5 Thread name Thread-0
10 Thread name Thread-0
15 Thread name Thread-0
20 Thread name Thread-0
25 Thread name Thread-0
100 Thread name Thread-1
200 Thread name Thread-1
300 Thread name Thread-1
400 Thread name Thread-1
500 Thread name Thread-1
Static synchronization
a. Static method belongs to class rather than object/instance of a class
b. prevents interference between threads (thread1 and thread2) accessing two different objects of a shared class.
public class Table {
public static synchronized void printTable(int n) {
for (int i = 1; i <= 5; i++) {
System.out.println(n * i);
try {
Thread.sleep(400);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class MyThread1 extends Thread {
Table table;
MyThread1(Table table) {
this.table = table;
}
public void run() {
table.printTable(5);
}
}
public class MyThread2 extends Thread {
Table table;
MyThread2(Table table) {
this.table = table;
}
public void run() {
table.printTable(100);
}
}
public class Main {
public static void main(String[] args) {
// two different objects
Table object1 = new Table();
Table object2 = new Table();
MyThread1 thread1 = new MyThread1(object1);
MyThread2 thread2 = new MyThread2(object2);
thread1.start();
thread2.start();
}
}
//output without using static synchronization
5
100
10
200
15
300
20
400
25
500
//output with static synchronization
5
10
15
20
25
100
200
300
400
500
Reentrant synchronization:
In Java, a reentrant synchronization is a synchronization mechanism that allows a thread to reacquire a lock it already holds, without blocking itself or any other threads. This means that a thread can acquire the same lock multiple times, without deadlocking or causing other issues. Reentrant synchronization is implemented using the synchronized
keyword in Java
public class ReentrantExample {
private static final Object lock = new Object();
public static void main(String[] args) {
synchronized (lock) {
System.out.println("Thread 1: First time acquiring the lock");
synchronized (lock) {
System.out.println("Thread 1: Second time acquiring the lock");
synchronized (lock) {
System.out.println("Thread 1: Third time acquiring the lock");
}
}
}
}
}
//all synchronized block acquires the same lock