Mastering Distributed Locks with Redis: From Bronze to Diamond Solutions
This article examines why local locks fail in distributed systems, introduces Redis‑based distributed locking, and walks through five progressive solutions—from a simple SETNX implementation to atomic Lua scripts—highlighting each approach's drawbacks and how to mitigate them.
1. Problems with Local Lock
Local locks (e.g., synchronized or lock) work for a single instance but cause data inconsistency when multiple micro‑services handle high‑concurrency requests, because each service can acquire its own lock independently.
In a scenario with 10 W requests forwarded to four services, each service may lock its thread, leading to divergent cache values and unexpected results.
2. What Is a Distributed Lock
A distributed lock ensures that only one thread across a cluster can access a critical section (e.g., a database) at a time.
Analogy: the lock is a door, and all concurrent threads are people trying to enter the room; only one person may be inside, and the door is locked until they leave.
3. Redis SETNX
Redis can serve as a shared place to store the lock. The SETNX command (SET if Not eXist) sets a key only when it does not already exist. set <key> <value> NX Example using Docker:
docker exec -it <container_id> redis-cli set wukong 1111 NXResult OK means the lock was acquired; subsequent attempts return nil.
4. Bronze Solution
4.1 Bronze Principle
All threads attempt SETNX. The first succeeds and holds the lock; others wait until the lock is released.
// 1. Acquire lock
Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "123");
if (lock) {
// 2. Execute business logic
List<TypeEntity> list = getDataFromDB();
// 3. Release lock
redisTemplate.delete("lock");
return list;
} else {
// 4. Sleep and retry
sleep(100);
return getTypeEntityListByRedisDistributedLock();
}4.2 Bronze Drawbacks
If the business code throws an exception or the server crashes, the lock is never released, causing a deadlock. Adding an automatic expiration mitigates this risk.
5. Silver Solution
After acquiring the lock, set an expiration time so the lock is cleared automatically.
// Set expiration after acquiring lock
redisTemplate.expire("lock", 10, TimeUnit.SECONDS);The two‑step process (acquire then set expiration) is not atomic; if a failure occurs between the steps, the lock may never expire.
6. Gold Solution
Use Redis’s atomic SET command with both NX and an expiration ( PX for milliseconds or EX for seconds).
# Set key with value and expiration atomically
set <key> <value> PX 5000 NX
# or
set <key> <value> EX 5 NXChecking the TTL confirms the key’s remaining lifetime.
ttl wukong7. Platinum Solution
Assign a unique identifier (UUID) to each lock value and verify it before deletion.
// 1. Generate UUID
String uuid = UUID.randomUUID().toString();
// 2. Acquire lock with expiration
Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", uuid, 10, TimeUnit.SECONDS);
if (lock) {
// Business logic
List<TypeEntity> list = getDataFromDB();
// 3. Verify lock ownership
String lockValue = redisTemplate.opsForValue().get("lock");
if (uuid.equals(lockValue)) {
// 4. Release lock
redisTemplate.delete("lock");
}
return list;
} else {
// Wait and retry
sleep(100);
return getTypeEntityListByRedisDistributedLock();
}Although the expiration prevents permanent deadlock, acquiring the lock and setting the expiration are still separate steps, so a failure between them can leave the lock without an expiration.
8. Diamond Solution
Use a Lua script to atomically check the lock value and delete it.
if redis.call('get',KEYS[1]) == ARGV[1] then
return redis.call('del',KEYS[1])
else
return 0
endExecute the script via redisTemplate.execute:
String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class),
Arrays.asList("lock"), uuid);9. Summary
The article starts from the limitations of local locks, introduces Redis‑based distributed locking, and presents five progressive solutions—Bronze, Silver, Gold, Platinum, and Diamond—detailing each method’s shortcomings and how to improve them, providing practical Java code and diagrams throughout.
GitHub : https://github.com/Jackson0714/PassJava-Platform Gitee : https://gitee.com/jayh2018/PassJava-Platform Tutorial Site : www.passjava.cn
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.
Su San Talks Tech
Su San, former staff at several leading tech companies, is a top creator on Juejin and a premium creator on CSDN, and runs the free coding practice site www.susan.net.cn.
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.
