Distributed Lock Implementation Approaches in Java: Database, Redis, and Zookeeper
This article explains the concept of distributed locks, compares three implementation methods—database unique indexes, Redis (using SETNX), and Zookeeper—provides detailed SQL table design and Java code examples for acquiring and releasing locks, and discusses reentrancy, lock release timing, and single‑point failure considerations.
Java's built‑in locks such as synchronized and those in the JUC package work only within a single JVM, making them unsuitable for distributed environments where multiple processes or machines compete for a resource. Distributed locks solve this problem.
Distributed Lock Implementation Schemes
There are three main approaches:
Database (unique index)
Cache (Redis, Memcached, Tair)
Zookeeper
Database‑based lock uses a unique index to guarantee exclusivity. A lock record is inserted with a business‑level unique key; if another contender tries to insert the same key, a unique‑index violation occurs, indicating lock acquisition failure.
Cache‑based lock (e.g., Redis) achieves the highest performance because operations are in‑memory. It typically relies on the SETNX command, which succeeds only when the key does not exist.
Zookeeper‑based lock creates an ephemeral node; the node’s uniqueness ensures exclusivity, similar to the Redis approach.
When implementing distributed locks, considerations include re‑entrancy, lock release timing, and single‑point failures.
Database‑Based Distributed Lock
Below is a simple implementation using a MySQL table.
Table Design
CREATE TABLE `distributed_lock` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`unique_mutex` varchar(255) NOT NULL COMMENT '业务防重id',
`holder_id` varchar(255) NOT NULL COMMENT '锁持有者id',
`create_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `mutex_index` (`unique_mutex`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;The `unique_mutex` column stores the business‑level lock identifier and is protected by a unique index.
Lock Acquisition
insert into distributed_lock(unique_mutex, holder_id) values ('unique_mutex','holder_id');If the insert succeeds, the lock is acquired; a duplicate‑key exception means the lock is already held.
Lock Release
delete from methodLock where unique_mutex='unique_mutex' and holder_id='holder_id';Releasing simply deletes the corresponding record.
Analysis
Re‑entrancy : The basic scheme is non‑re‑entrant. To make it re‑entrant, check whether the existing record’s `holder_id` matches the current contender before deciding.
Lock release timing : If a process crashes, the lock record may remain. A common solution is to compare the record’s creation time with the current time and delete stale locks before attempting a new lock.
Database single‑point failure : A single database can become a bottleneck; high‑availability solutions such as MySQL MHA should be considered.
Cache‑Based Distributed Lock (Redis Example)
Using Jedis to communicate with Redis.
Lock Acquisition
public class RedisTool {
private static final String LOCK_SUCCESS = "OK";
private static final String SET_IF_NOT_EXIST = "NX";
private static final String SET_WITH_EXPIRE_TIME = "PX";
/**
* Acquire lock
*/
public static boolean getDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) {
String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
return "OK".equals(result);
}
}The `SET` command with parameters `NX` and `PX` ensures atomic lock acquisition with an expiration time, preventing deadlocks if the holder crashes.
Lock Release
public class RedisTool {
private static final Long RELEASE_SUCCESS = 1L;
/**
* Release lock
*/
public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) {
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
return RELEASE_SUCCESS.equals(result);
}
}The release uses a Lua script to atomically verify the owner and delete the key, avoiding race conditions where the lock might be reassigned before deletion.
Analysis
Re‑entrancy : The basic implementation is non‑re‑entrant; to support re‑entrancy, after `SET_IF_NOT_EXIST` check whether the existing value matches the current requester.
Lock release timing : The key’s expiration ensures automatic release if the holder crashes.
Redis single‑point issue : Deploy Redis in a clustered, high‑availability setup to avoid a single point of failure.
Zookeeper‑Based Distributed Lock
Lock/Unlock Process
Clients create an ephemeral sequential node; the smallest node acquires the lock. Others set a watcher on the preceding node and wait for its deletion. Upon unlocking, the node is deleted, notifying the next contender.
Analysis
Re‑entrancy : By storing host and thread information in the node, a client can recognize its own lock and re‑enter.
Lock release timing : Zookeeper automatically removes the ephemeral node if the session expires.
Single‑point issue : Zookeeper runs as a quorum; as long as a majority of servers are up, the service remains available.
Curator Implementation
// Acquire lock with timeout, supports re‑entrancy
public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
try {
return interProcessMutex.acquire(timeout, unit);
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
// Release lock
public boolean unlock() {
try {
interProcessMutex.release();
} catch (Throwable e) {
log.error(e.getMessage(), e);
} finally {
executorService.schedule(new Cleaner(client, path), delayTimeForClean, TimeUnit.MILLISECONDS);
}
return true;
}The Curator library abstracts Zookeeper details, providing a convenient API for distributed locking.
Comparison of the Three Schemes
(A comparison table or diagram would typically be placed here.)
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.
Architecture Digest
Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.
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.
