Mastering Distributed Locks in Java: From Databases to Redis and Zookeeper
This article explains why distributed locks are needed in Java applications, outlines the essential conditions they must satisfy, and compares three practical implementations—database‑based, Redis‑based, and Zookeeper‑based—providing code snippets and performance considerations for each.
Why Use Distributed Locks
When a Java application scales from a single JVM to a cluster, shared variables that were previously synchronized with local locks become inconsistent across multiple JVMs, requiring a cross‑process mutual exclusion mechanism known as a distributed lock.
Conditions a Distributed Lock Must Meet
1. Only one thread across the entire distributed system can hold the lock at a time. 2. High availability for acquiring and releasing the lock. 3. High performance for lock operations. 4. Re‑entrancy support. 5. Automatic expiration to avoid deadlocks. 6. Non‑blocking behavior – failure to acquire returns immediately.
Three Common Implementation Approaches
The CAP theorem tells us that a distributed system cannot simultaneously guarantee consistency, availability, and partition tolerance; most systems sacrifice strong consistency for high availability, aiming for eventual consistency.
• Database‑based lock • Redis‑based lock • Zookeeper‑based lock
Database‑Based Implementation
The core idea is to create a table with a unique index on a method name. Inserting a row acquires the lock; deleting the row releases it.
Step 1: Create the lock table.
Step 2: Insert a row with the method name.
Step 3: Delete the row after execution.
Key limitations:
Lock availability and performance depend on the database’s own reliability.
Not re‑entrant without extra columns to track owner thread.
No automatic expiration; stale rows require cleanup tasks.
Non‑blocking – callers must retry manually.
Additional complexity and resource overhead.
Redis‑Based Implementation
Redis is chosen for its high performance and simple command set.
Key commands: SETNX key value – set only if key does not exist. EXPIRE key seconds – set automatic timeout to avoid deadlocks. DEL key – release the lock.
Implementation steps:
Use SETNX to acquire the lock and immediately set an expiration with EXPIRE. Store a random UUID as the lock value.
Optionally set a maximum wait time for acquiring the lock.
When releasing, compare the stored UUID; if it matches, delete the key.
Sample code (illustrated as images):
Testing with 50 threads simulating a flash‑sale shows ordered results when the lock is active, and chaotic results when the lock is disabled.
Zookeeper‑Based Implementation
Zookeeper provides a hierarchical namespace where only one temporary sequential node can exist per lock path.
Steps:
Create a directory /mylock.
Thread A creates an EPHEMERAL‑SEQUENTIAL node under /mylock.
All nodes are listed; the smallest sequence number acquires the lock.
Other threads watch the next‑smallest node; when it disappears, they retry.
After processing, the owner deletes its node, triggering the watch.
Apache Curator’s InterProcessMutex simplifies this pattern with acquire() and release() methods.
Pros: high availability, re‑entrancy, blocking lock support, automatic expiration handling. Cons: higher overhead due to frequent node creation/deletion, slower than Redis.
Conclusion
No single implementation fits all scenarios; choose based on performance, availability, and feature requirements. Distributed locks are essential for controlling access to shared resources in clustered environments, but careful tuning of timeout and retry logic is necessary for production use.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Backend Technology
Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
