Strict Two Phase Locking: Definition, Example, and Use Cases
Strict Two Phase Locking (Strict 2PL) is a concurrency control method in databases where all locks held by a transaction are released only after the transaction commits or aborts. This ensures serializability and prevents other transactions from seeing intermediate changes, maintaining data consistency.How It Works
Strict Two Phase Locking works by dividing a transaction's life into two phases: a growing phase where it acquires locks but does not release any, and a shrinking phase where it releases all locks only after the transaction finishes (commits or aborts). This means no other transaction can access the locked data until the current transaction is fully done.
Imagine you are writing a letter and locking the drawer where you keep your drafts. You keep the drawer locked while writing and only unlock it after finishing the letter. This way, no one else can peek or change your draft midway, ensuring your work stays consistent.
By holding all locks until the end, strict 2PL prevents problems like dirty reads, where one transaction sees uncommitted changes from another, making the database safe and reliable.
Example
This example simulates two transactions accessing a shared data item using strict two phase locking to avoid conflicts.
import java.util.HashMap; import java.util.Map; class LockManager { private final Map<String, String> locks = new HashMap<>(); public synchronized boolean acquireLock(String transaction, String dataItem) { if (!locks.containsKey(dataItem)) { locks.put(dataItem, transaction); System.out.println(transaction + " acquired lock on " + dataItem); return true; } else if (locks.get(dataItem).equals(transaction)) { return true; // already locked by this transaction } else { System.out.println(transaction + " waiting for lock on " + dataItem); return false; } } public synchronized void releaseLocks(String transaction) { locks.entrySet().removeIf(entry -> entry.getValue().equals(transaction)); System.out.println(transaction + " released all locks"); } } class Transaction implements Runnable { private final String name; private final LockManager lockManager; public Transaction(String name, LockManager lockManager) { this.name = name; this.lockManager = lockManager; } @Override public void run() { // Growing phase: acquire locks while (!lockManager.acquireLock(name, "DataItem1")) { try { Thread.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } // Simulate work System.out.println(name + " is processing DataItem1"); try { Thread.sleep(200); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } // Commit phase: release locks lockManager.releaseLocks(name); System.out.println(name + " committed transaction"); } } public class Strict2PLExample { public static void main(String[] args) throws InterruptedException { LockManager lockManager = new LockManager(); Thread t1 = new Thread(new Transaction("T1", lockManager)); Thread t2 = new Thread(new Transaction("T2", lockManager)); t1.start(); Thread.sleep(50); // Start T2 shortly after T1 t2.start(); t1.join(); t2.join(); } }
When to Use
Strict Two Phase Locking is best used in database systems where data consistency and correctness are critical, such as banking, booking systems, and inventory management. It prevents problems like dirty reads and ensures that transactions appear to run one after another, even if they run at the same time.
Use strict 2PL when you want to avoid complex errors caused by concurrent data access and when the cost of waiting for locks is acceptable compared to the risk of inconsistent data.
Key Points
- Strict 2PL holds all locks until transaction commit or abort.
- Prevents dirty reads and ensures serializability.
- Divides transaction into growing and shrinking phases.
- Commonly used in systems requiring strong data consistency.
- May cause waiting or blocking but improves correctness.