Open In App

Java Lock Framework vs Thread Synchronization

Last Updated : 11 Jan, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

In Java, thread synchronization is achieved using the Lock framework which is present in the java.util.concurrent package. Synchronization ensures that only one thread can access a resource at a time by preventing issues like data corruption or inconsistency. Java offers two primary mechanisms for achieving synchronization, which are the Lock framework and synchronized blocks. Both serve similar purposes and they offer different levels of flexibility and control. The Lock framework provides a more sophisticated approach when dealing with multiple threads and shared resources.

In this article, we will explore the differences between the Lock framework and thread synchronization. Both techniques ensure that multiple threads do not access shared resources simultaneously.

Difference Between Lock Framework and Thread Synchronization

FeaturesLock FrameworkThread Synchronization (synchronized)
FlexibilityMore flexible. Allows multiple locks for different methods.

Limited flexibility. Only one lock can be applied per method or class.

Concurrency

Allows higher concurrency by using different locks for different tasks.

Less concurrency due to locking the entire method or class.
Control Over LockingProvides explicit control over when to lock and unlock.Implicit locking with no control over the exact limit.
List of waiting threadsThe list of waiting threads can be seen using the Lock frameworkNot possible with synchronized.
Deadlock Prevention

Offers better strategies to avoid deadlocks using try-lock mechanisms.


Less control over deadlock prevention.

Interruptible

Supports interruptible lock acquisition (e.g., lock.tryLock())

Synchronized blocks are non-interruptible.

Lock Framework

The Lock framwork is primarily based on the Lock interface, with ReentrantLock being the most commonly used implementation. Not like the synchronized blocks but the Lock framework allows explicit locking and unlocking of resources, providing greater control over thread access. It supports features such as non-blocking locking with tryLock().

Example: Lock Framework using ReentrantLock

Java
// Java program to demonstrate how Lock works
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Geeks {
  
    public static void main(String[] args) {
        TestResource resource = new TestResource();

        // Create a fixed number of threads (2 display and 2 read)
        for (int i = 0; i < 2; i++) {
            new Thread(new DisplayJob(resource), "Thread " + (i + 1)).start();
        }
        for (int i = 2; i < 4; i++) {
            new Thread(new ReadJob(resource), "Thread " + (i + 1)).start();
        }
    }
}

class DisplayJob implements Runnable {
    private final TestResource resource;

    DisplayJob(TestResource resource) {
        this.resource = resource;
    }

    @Override
    public void run() {
        resource.displayRecord(new Object());
    }
}

class ReadJob implements Runnable {
    private final TestResource resource;

    ReadJob(TestResource resource) {
        this.resource = resource;
    }

    @Override
    public void run() {
        resource.readRecord(new Object());
    }
}

class TestResource {
    private final Lock displayLock = new ReentrantLock();
    private final Lock readLock = new ReentrantLock();

    public void displayRecord(Object document) {
        displayLock.lock();
      
        try {
          
            Thread.sleep(50);
            System.out.println(Thread.currentThread().getName() + ": Displaying...");
          
        } catch (InterruptedException e) {
            e.printStackTrace();
          
        } finally {
            displayLock.unlock();
        }
    }

    public void readRecord(Object document) {
        readLock.lock();
        try {
          
            Thread.sleep(50); 
            System.out.println(Thread.currentThread().getName() + ": Reading...");
          
        } catch (InterruptedException e) {
            e.printStackTrace();
          
        } finally {
            readLock.unlock();
        }
    }
}

Output
Thread 1: Displaying...
Thread 3: Reading...
Thread 2: Displaying...
Thread 4: Reading...

Explaination: In this example, we use the ReentrantLock class to synchronize access to a shared resource. Two types of threads, DisplayJob and ReadJob, compete for access to the TestResource. By using separate ReentrantLock objects (displayLock and readLock) for the displayRecord() and readRecord() methods, the code ensures that these operations can occur concurrently without interfering with each other.

Thread Synchronization

Thread synchronization is the process of controlling the order of access to shared resources among multiple threads to prevent data corruption and ensure correct program execution. in the present time we use Locks to achieve thread synchronization. It is achieved by using Synchronized Keyword.

Example: Thread Synchronization using synchronized

Java
// Java program to demonstrate thread synchronization
class Counter {
  
    // counter variable
    private int c = 0; 

    // synchronized method
    public synchronized void increment() { 
        c++; 
    }

    public int getCount() {
        return c;
    }
}

public class Geeks {
  
    public static void main(String[] args) 
      throws InterruptedException {
      
        Counter o = new Counter();
        Thread t1 = new Thread(() -> {
          
            for (int i = 0; i < 1000; i++) {
                o.increment();
            }
        });
      
        Thread t2 = new Thread(() -> {
          
            for (int i = 0; i < 1000; i++) {
                o.increment();
            }
          
        });

        t1.start();
        t2.start();

        t1.join();
        t2.join();

        System.out.println("Count: " + o.getCount()); 
    }
}

Output
Count: 2000

Explanation: In this example, the Counter class has a shared count variable. The increment() method is synchronized and ensures that only one thread can access and modify the count variable at a time. This prevents race conditions where multiple threads might try to increment the counter simultaneously that leads to incorrect results. The synchronized block guarantees that the counter is incremented correctly even with multiple threads running. 



Next Article
Article Tags :
Practice Tags :

Similar Reads