Tuesday, November 19, 2024
Google search engine
HomeLanguagesJavaLimitations of synchronization and the uses of static synchronization in multithreading

Limitations of synchronization and the uses of static synchronization in multithreading

Multithreading feature of java is the feature around which the concept revolves as it allows concurrent execution of two or more parts of a program for maximum utilization of CPU. Each part of such a program is called a thread. So, threads are lightweight processes within a process where as we all know threads can be created by using two mechanisms as listed:

  1. Extending the Thread class
  2. Implementing the Runnable Interface

If multiple threads access a single resource at a time then there exists a possibility of data racing or bad output. Let us understand this with the help of a story. Let us take the example of data racing in multithreading to perceive the limitations of synchronization and the uses of static synchronization. Let us lick off directly with the data racing in multithreading.

Implementation:

Shubham and Sharmistha was planning a date and tried to book movie tickets. Unfortunately, only 1 ticket was available. Shubham who was a genius Java programmer knew a trick and requested 1 ticket simultaneously for both of them at the same time. The naive ticket booking system assigned 2 threads and passed them through the book method. In the end of the procedure, both of them got 1 ticket each and the number of tickets left was -1!

Illustration: Data racing in multithreading

Java




// Java program to show Data racing in multithreading.
 
// Helper class 1
class book {
    int tickets = 1;
    // method to book movie ticket
    void book(int request, String name)
    {
        // logic to book ticket
        if (tickets >= request) {
            System.out.println(name + " booked " + request
                               + " ticket.");
            tickets = tickets - 1;
            System.out.println("Tickets left: " + tickets);
        }
        else {
            System.out.println("No tickets are available.");
        }
    }
}
// Helper class 2, extending Thread class.
// book method is called from this class using the object
// passed from main class.
class myThread extends Thread {
    book obj;
    int n;
    String name;
    myThread(book obj, String name, int n)
    {
        this.obj = obj;
        this.n = n;
        this.name = name;
    }
    // runs threads
    public void run() { obj.book(n, name); }
}
// Driver class
public class GFG {
    // Driver method
    public static void main(String[] args)
    {
        // Creating object "obj" of book class and passing
        // it to myThread class
        book obj = new book();
        myThread t1 = new myThread(obj, "Shubham", 1);
        myThread t2 = new myThread(obj, "Sharmistha", 1);
        // When a program calls the start() method, a new
        // thread is created and then the run() method is
        // executed.
 
        // Starting threads created above
        t1.start();
        t2.start();
    }
}


Output-

Shubham booked 1 ticket.
Sharmistha booked 1 ticket.
Tickets left: 0
Tickets left: -1

Number of tickets can not be negative. To handle this problem engineers came up with the synchronization concept.

Synchronization- we provide a lock to the object and declare a sensitive area(withdraw method). An object can have multiple threads but the sensitive area can only be accessed by 1 thread at a time.

Illustration: Handling data racing due to multithreading using synchronization.

Java




// Java program to handle data racing due to
// multithreading using synchronization.
 
// Helper class 1
class book {
    int tickets = 1;
    // synchronized method to book movie ticket
    synchronized void book(int request, String name)
    {
        // logic to book ticket
        if (tickets >= request) {
            System.out.println(name + " booked " + request
                               + " ticket.");
            tickets = tickets - 1;
            System.out.println("Tickets left: " + tickets);
        }
        else {
            System.out.println("No tickets are available.");
        }
    }
}
// Helper class 2, extending Thread class.
// book method is called from this class using the object
// passed from main class.
class myThread extends Thread {
    book obj;
    int n;
    String name;
    myThread(book obj, String name, int n)
    {
        this.obj = obj;
        this.n = n;
        this.name = name;
    }
    // runs threads
    public void run() { obj.book(n, name); }
}
// Driver class
public class GFG {
    // Driver method
    public static void main(String[] args)
    {
        // Creating object "obj" of book class and passing
        // it to myThread class
        book obj = new book();
        myThread t1 = new myThread(obj, "Shubham", 1);
        myThread t2 = new myThread(obj, "Sharmistha", 1);
        // When a program calls the start() method, a new
        // thread is created and then the run() method is
        // executed.
 
        // Starting threads created above
        t1.start();
        t2.start();
    }
}


Output-

Shubham booked 1 ticket.
Tickets left: 0
No tickets are available.

Limitations of synchronization:

If we have multiple thread from 1 object than synchronization will handle the data racing or bad output. What will happen if multiple threads are assigned from multiple objects? this will again result in bad output or data racing.

Illustration: Cons of synchronization when multiple threads gets assigned from multiple objects.

Java




// Java program to illustrate limitations of
// synchronization.
 
// Helper class 1
class book {
    // tickets is static so all book objects have the same ticket count
    static int tickets = 1;
    // synchronized method to book movie ticket
    synchronized void book(int request, String name)
    {
        // logic to book ticket
        if (tickets >= request) {
            System.out.println(name + " booked " + request
                               + " ticket.");
            tickets = tickets - 1;
            System.out.println("Tickets left: " + tickets);
        }
        else {
            System.out.println("No tickets are available.");
        }
    }
}
// Helper class 2, extending Thread class.
// book method is called from this class using the object
// passed from main class.
class myThread extends Thread {
    book obj;
    int n;
    String name;
    myThread(book obj, String name, int n)
    {
        this.obj = obj;
        this.n = n;
        this.name = name;
    }
    // runs threads
    public void run() { obj.book(n, name); }
}
// Driver class
public class GFG {
    // Driver method
    public static void main(String[] args)
    {
        // Creating multiple objects "obj" and "obj2" of
        // book class and passing it to myThread class.
        book obj = new book();
        book obj2 = new book();
        myThread t1 = new myThread(obj, "Shubham", 1);
        myThread t2 = new myThread(obj2, "Sharmistha", 1);
        // When a program calls the start() method, a new
        // thread is created and then the run() method is
        // executed.
 
        // Starting threads created above
        t1.start();
        t2.start();
    }
}


Output-

Sharmistha booked 1 ticket.
Shubham booked 1 ticket.
Tickets left: 0
Tickets left: -1

We have only 1 ticket but due to data racing both of them booked successfully! To handle this problem we need to study static synchronization.

Static Synchronization- Say we have 5 objects. Each objects have multiple threads. Now the sensitive area will be accessed by 5 threads at a time!

To handle this problem engineers came up with the idea of Static synchronization. We provide a lock to the class. The class will select 1 object at a time. The object in turn will choose 1 thread and pass it through the sensitive area. 

Illustration: Handling data racing using static synchronization.

Java




// Java program to handle data racing using static
// synchronization.
 
// Helper class 1
class book {
    static int tickets = 1;
    // static synchronized method to book movie ticket
    static synchronized void book(int request, String name)
    {
        // logic to book ticket
        if (tickets >= request) {
            System.out.println(name + " booked " + request
                               + " ticket.");
            tickets = tickets - 1;
            System.out.println("Tickets left: " + tickets);
        }
        else {
            System.out.println(
                name + ", No tickets are available.");
        }
    }
}
// Helper class 2, extending Thread class.
// book method is called from this class using the object
// passed from main class.
class myThread extends Thread {
    book obj;
    int n;
    String name;
    myThread(book obj, String name, int n)
    {
        this.obj = obj;
        this.n = n;
        this.name = name;
    }
    // runs Threads
    public void run() { obj.book(n, name); }
}
// Driver class
public class GFG {
    // Driver method
    public static void main(String[] args)
    {
        // Creating object "obj" of book class and passing
        // it to myThread class
        book obj = new book();
        book obj2 = new book();
        myThread t1 = new myThread(obj, "Shubham", 1);
        myThread t2 = new myThread(obj2, "Sharmistha", 1);
        // When a program calls the start() method, a new
        // thread is created and then the run() method is
        // executed.
 
        // Starting threads created above
        t1.start();
        t2.start();
    }
}


Output-

Shubham booked 1 ticket.
Tickets left: 0
Sharmistha, No tickets are available.

Using static synchronization, we have prepared a system to prevent illegal ticket booking.

Conclusion-

  1. When we have multiple threads from a single object than we can use synchronization to lock the object to pass 1 thread at a time and prevent bad output.
  2. If multiple threads are assigned from multiple objects than we can not use synchronization. In such cases providing lock to the object will result in data racing. we need to use static synchronization and provide lock to the class. The class will select 1 object at a time. The object in turn will choose 1 thread and pass it to the sensitive area.
RELATED ARTICLES

Most Popular

Recent Comments