Thread Synchronization in Java!!!

What are threads? A thread is a very light-weight process or we can say the smallest part of the process that allows the program to run efficiently.

What is thread synchronization? Often threads need to share data but they shouldn't try to change and access the same data at the same time to deal with this we need thread synchronization which helps in the cooperation of the threads.

There are two types of thread synchronization:

  1. Mutual exclusive: It helps threads to keep away from interfering with each other while sharing data this can be done in a few ways by synchronized method, synchronized block or static synchronization.

    Synchronization is built around an internal entity known as the lock or monitor. Every object has a lock associated with it. By convention, a thread that needs consistent access to an object's fields has to acquire the object's lock before accessing them, and then release the lock when it's done with them.

    If you declare any method as synchronized, it is known as a synchronized method. The synchronized method is used to lock an object for any shared resource.

    When a thread invokes a synchronized method, it automatically acquires the lock for that object and releases it when the thread completes its task.

// this is example of thread synchronization by using synchronization methods

import java.io.*;

class Table {
    synchronized void printTable(int n) {
        for (int i = 0; i < 5; i++) {
            System.out.println(n * i);
        }
        try {
            Thread.sleep(400); // this function causes current thread to suspend for some time 
        } catch (InterruptedException e) {
            System.out.println(e);
        }
    }
}

class Mythread1 extends Thread {
    Table t;

    Mythread1(Table t) {
        this.t = t;
    }

    public void run() { //public void run() is the entry point for the code that a thread will execute when it is started.
        t.printTable(5);
    }
}

class Mythread2 extends Thread {
    Table t;

    Mythread2(Table t) {
        this.t = t;
    }

    public void run() {
        t.printTable(50);
    }
}

public class Main {
    public static void main(String[] args) {
        Table obj = new Table();
        Mythread1 t1 = new Mythread1(obj);
        Mythread2 t2 = new Mythread2(obj);
        t1.start();
        t2.start();
    }
}
// implication of thread synchronization using synchronization block

import java.io.*;

class A implements Runnable {
    int token = 1;

    public void run() {
        synchronized (this) {
            Thread t = Thread.currentThread();
            String name = t.getName(); // Corrected capitalization of "getName"
            System.out.println(token + "...allocated to " + name); // Added space after "allocated to"
            token++; // Increment token for the next thread
        }
    }
}

public class Main {
    public static void main(String[] args) {
        A a1 = new A();
        Thread t1 = new Thread(a1);
        Thread t2 = new Thread(a1);
        Thread t3 = new Thread(a1);
        t1.setName("t1"); // Corrected capitalization of "setName"
        t2.setName("t2");
        t3.setName("t3");
        t1.start();
        t2.start();
        t3.start();
    }
}

In summary, thread joining is used to control the order of execution of threads, allowing one thread to wait for another to finish, while thread synchronization is used to control access to shared resources and ensure data integrity in a multithreaded environment. They serve different purposes and are often used together to create robust multithreaded applications.

If a method is declared as synchronized that method’s complete logic is executed in sequence from multiple threads by using the same object. If we declare the block as synchronized, only the statements written inside that block are executed sequentially not complete method logic.