Understanding Distributed Locks: Features, Implementations, and Best Practices
This article explains why distributed locks are needed, outlines their five essential properties, compares common implementation methods such as database, ZooKeeper, and Redis locks, and provides Java code examples for acquiring, releasing, re‑entering, and safely extending locks with watchdog mechanisms.
Distributed locks ensure that at any moment only one JVM process thread executes a critical section across multiple services and nodes.
The lock provides five key properties: mutual exclusion, dead‑lock avoidance, ownership verification (only the lock holder can release), re‑entrancy, and fault tolerance.
Common implementations include database locks, ZooKeeper‑based locks, and Redis‑based locks.
Example Java code shows a simple usage pattern with a RedisLock object, where the lock is acquired before business logic and released in a finally block to guarantee release even on exceptions.
public static void doSomething() {
RedisLock redisLock = new RedisLock(jedis);
try {
redisLock.lock();
// business logic
System.out.println(Thread.currentThread().getName() + " processing...");
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + " done");
} finally {
redisLock.unlock();
}
}To prevent lock loss when a process crashes, a timeout is set (e.g., 1 s) using Redis SET … EX … NX . The timeout can be extended automatically by a watchdog thread that periodically refreshes the expiration.
public class RedisLockIdleThreadPool {
private String threadAddLife_lua = "if redis.call(\"exists\", KEYS[1]) == 1\n" +
"then\n" +
" return redis.call(\"expire\", KEYS[1], ARGV[1])\n" +
"else\n" +
" return 0\n" +
"end";
// scheduler refreshes lock every 300 ms
}Re‑entrancy is achieved by storing a unique token (UUID or APP_ID + ThreadId) as the lock value and using a Lua script to compare the token before deletion, ensuring only the owner can release the lock.
String releaseLock_lua = "if redis.call(\"get\",KEYS[1]) == ARGV[1] then " +
"return redis.call(\"del\", KEYS[1]) else return 0 end";Additional attributes such as re‑entrancy count and maximum timeout can be kept in a Redis hash, and their expirations are tied to the lock key to avoid permanent dead‑locks.
The article concludes that understanding these five characteristics and the underlying mechanisms helps developers apply distributed locks correctly without over‑locking or compromising system availability.
High Availability Architecture
Official account for High Availability Architecture.
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.