[post-views]
In this lesson, you will learn.
1. Banking Analogy: Suppose a bank teller desk where only one customer can be served at a time. If multiple customers try to interact with the teller simultaneously, they may cause confusion or errors (like incorrect withdrawals or deposits).
Now, we can consider
Teller Desk: Shared Resource
Customer: Thread
2. Bridge Analogy: Consider a narrow bridge that can only accommodate one vehicle at a time. If vehicles from both ends try to cross simultaneously, accidents or gridlock could occur.
Now, we can consider
Bridge: Shared Resource
Vehicle: Thread
In both analogies, we need to design a mechanism to ensure that only one customer can be served at the bank teller desk and only one person crosses the bridge at any given time to maintain safety and data consistency.
Synchronization is a process that ensures that a shared resource is only used by one thread at a time when multiple threads need access to it.
Without synchronization, multiple threads can interfere with each other, leading to inconsistent or erroneous behavior.
Synchronization is essential when threads interact with shared data or objects.
Here is the process of how multiple thread works in the synchronization.
Example: Imagine an office where multiple employees need to print their documents using a single shared printer. If there is no orderly process or queue to access the printer, several people may attempt to print their documents at the same time. As a result:
You can synchronize your code in either of two ways. Both involve the use of the synchronized keyword.
When a thread is inside a synchronized method, all other threads that try to call it (or any other synchronized method) on the same instance have to wait.
Syntax
public synchronized void synchronizedMethod()
{
// Method code that requires synchronization
}
A synchronized block ensures that a particular section of code can only be executed by one thread at a time.
This ensures that only one thread can execute a synchronized block at any given time.
The syntax of a synchronized block is as follows:
synchronized(objRef) {
// statements to be synchronized
}
Here, objRef is a reference to the object being synchronized.
The following program may or may not print a counter value in the sequence and every time it produces a different result based on the availability of the CPU for a thread.
package synchronization;
class Counter {
static int count = 0;
public static void setCount() {
for (int i = 1; i <=1000; i++) {
Counter.count++;
}
}
}
class MyThread extends Thread {
private int threadNo;
public MyThread(int threadNo) {
this.threadNo = threadNo;
}
@Override
public void run() {
Counter.setCount();
System.out.println("The thread "+threadNo+" is over.");
}
}
public class CounterMain {
public static void main(String[] args) throws InterruptedException {
MyThread t1 = new MyThread(1);
MyThread t2 = new MyThread(2);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("The value of the counter is: "+Counter.count);
}
}
Output – First Run
The thread 1 is over.
The thread 2 is over.
The value of the counter is: 1290
Output – Second Run
The thread 2 is over.
The thread 1 is over.
The value of the counter is: 1070
Explanation
In the above example, each thread increments the counter 1000 times. Ideally, the counter should reach 2,000. However, due to concurrent modifications without synchronization, you will likely see a different, incorrect result every time you run this program.
Now, let’s add synchronization to ensure that the counter increments correctly without interference between threads:
package synchronization;
class Counter {
static int count = 0;
// Increment the counter without synchronization
public synchronized static void setCount() {
for (int i = 1; i <=1000; i++) {
Counter.count++;
}
}
}
class MyThread extends Thread {
private int threadNo;
public MyThread(int threadNo) {
this.threadNo = threadNo;
}
@Override
public void run() {
Counter.setCount();
System.out.println("The thread "+threadNo+" is over.");
}
}
public class CounterMain {
public static void main(String[] args) throws InterruptedException {
MyThread t1 = new MyThread(1);
MyThread t2 = new MyThread(2);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("The value of the counter is: "+Counter.count);
}
}
Output
The thread 1 is over.
The thread 2 is over.
The value of the counter is: 2000
count
variable simultaneously. setCount()
method synchronized, we lock the counter instance for each increment operation, ensuring that only one thread can execute the method at any given time.
package synchronization;
class NumberPrinter
{
void printTable(int n) {
synchronized(this)//synchronized block
{
for(int i=1;i<=5;i++){
System.out.println(n*i);
try{
Thread.sleep(400);
}catch(Exception e){System.out.println(e);}
}
}
for (int i = 1; i < 5; i++) {
try {
Thread.sleep(2500);
System.out.println(Thread.currentThread()+" is executing");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}//end of the method
}
class MyThread1 extends Thread{
NumberPrinter t;
MyThread1(NumberPrinter t){
this.t=t;
}
public void run(){
t.printTable(3);
}
}
class MyThread2 extends Thread{
NumberPrinter t;
MyThread2(NumberPrinter t){
this.t=t;
}
public void run(){
t.printTable(10);
}
}
public class SynchronizedTable{
public static void main(String args[]){
NumberPrinter obj = new NumberPrinter();//only one object
MyThread1 t1=new MyThread1(obj);
MyThread2 t2=new MyThread2(obj);
t1.start();
t2.start();
}
}
Output: First Run
10
20
30
40
50
3
6
9
12
15
Thread[Thread-1,5,main] is executing
Thread[Thread-0,5,main] is executing
Thread[Thread-1,5,main] is executing
Thread[Thread-0,5,main] is executing
Thread[Thread-1,5,main] is executing
Thread[Thread-0,5,main] is executing
Thread[Thread-1,5,main] is executing
Thread[Thread-0,5,main] is executing
Output: Second Run
3
6
9
12
15
10
20
30
40
50
Thread[Thread-0,5,main] is executing
Thread[Thread-1,5,main] is executing
Thread[Thread-0,5,main] is executing
Thread[Thread-1,5,main] is executing
Thread[Thread-0,5,main] is executing
Thread[Thread-1,5,main] is executing
Thread[Thread-0,5,main] is executing
Thread[Thread-1,5,main] is executing
There are no reviews yet. Be the first one to write one.
You must be logged in to submit a review.