Backend Development 20 min read

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.

High Availability Architecture
High Availability Architecture
High Availability Architecture
Understanding Distributed Locks: Features, Implementations, and Best Practices

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.

JavaConcurrencyRedisDistributed Lockwatchdogreentrancy
High Availability Architecture
Written by

High Availability Architecture

Official account for High Availability Architecture.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.