Backend Development 22 min read

Mastering Distributed Locks with Redis: From Simple SETNX to RedLock and Redisson

This article explains how to implement distributed locks using Redis, covering basic SETNX/EXPIRE techniques, common pitfalls, atomic Lua scripts, the RedLock algorithm, and practical Redisson usage, while providing Java code examples and best‑practice recommendations.

Top Architect
Top Architect
Top Architect
Mastering Distributed Locks with Redis: From Simple SETNX to RedLock and Redisson

1. Overview

In multithreaded environments Java uses

synchronized

or

ReentrantLock

for local locks, but distributed systems need a mechanism to synchronize threads across nodes.

Distributed lock characteristics

Mutual exclusion: only one thread can hold the lock at a time.

Reentrancy: the same thread can acquire the lock multiple times on the same node.

Lock timeout: similar to J.U.C. locks, supports expiration to avoid deadlocks.

High performance and availability: lock/unlock must be efficient and highly available.

Blocking and non‑blocking: the lock can be released promptly from a blocked state.

2. Rough Redis implementation

Redis is a shared storage system suitable for distributed locks because of its high read/write performance.

The

SET

command with the

NX

option implements "set if not exists" semantics:

If the key does not exist, the command succeeds and the lock is acquired.

If the key exists, the command fails and the lock is not acquired.

To release the lock, delete the key.

Set an appropriate expiration time to avoid deadlocks.

<code>// Try to acquire lock
if (setnx(key, 1) == 1) {
    // Set expiration time
    expire(key, 30);
    try {
        // TODO business logic
    } finally {
        // Release lock
        del(key);
    }
}</code>

The above implementation has several problems:

Non‑atomic operations: multiple commands are not atomic, leading to possible deadlocks.

Lock mis‑release: if a thread blocks and the lock expires, another thread may acquire it, and the original thread may later delete the lock belonging to the other thread.

Business timeout auto‑unlock: the lock may be released while business logic is still running.

Non‑reentrant lock: the implementation does not support reentrancy.

3. Solving remaining issues

3.1 Mis‑delete scenario

When a thread holding the lock blocks and its TTL expires, the lock is automatically released; another thread can acquire it, and later the original thread may mistakenly delete the new lock.

3.2 Solution

Store the thread identifier when acquiring the lock.

When releasing, verify that the stored identifier matches the current thread.

<code>// Try to acquire lock
if (setnx(key, "currentThreadId") == 1) {
    expire(key, 30);
    try {
        // TODO business logic
    } finally {
        if ("currentThreadId".equals(get(key))) {
            del(key);
        }
    }
}</code>

This ensures only the owner can release the lock and enables reentrancy by incrementing a counter for the same thread.

3.3 Atomicity guarantee

SETNX and EXPIRE are not atomic; if the server crashes after SETNX succeeds but before EXPIRE, the lock may never expire. Use a Lua script to combine the operations atomically:

<code>-- Set expiration atomically
if (redis.call('setnx', KEYS[1], ARGV[1]) < 1) then
    return 0;
end;
redis.call('expire', KEYS[1], tonumber(ARGV[2]));
return 1;
-- Delete lock atomically
if (redis.call('get', KEYS[1]) == ARGV[1]) then
    return redis.call('del', KEYS[1]);
end;
return 0;</code>

Calling this script from Java provides an atomic lock acquisition and release.

3.4 Automatic timeout unlock

If a thread's execution exceeds the TTL, the lock will still expire. One approach is to set a long TTL, but a better solution is to start a watchdog thread that renews the TTL before it expires.

4. Pros and cons of Redis‑based locks

Advantages

High performance.

Easy to implement using

SETNX

.

Avoids single‑point failure because Redis can be clustered.

Disadvantages

Choosing an appropriate timeout is difficult.

In master‑slave replication the data is asynchronous; a master failure before replication can cause lock loss.

5. Cluster issues

5.1 Master‑slave cluster

If a lock is set on the master but not yet replicated to the slave, and the master crashes, the lock is lost.

5.2 Split‑brain

Network partitions can cause multiple masters, leading to duplicate locks.

6. RedLock

RedLock is an algorithm that acquires locks on multiple independent Redis nodes. If a client obtains locks on a majority of nodes (N/2+1) within the lock’s TTL, the lock is considered acquired.

Get current Unix time in milliseconds.

Try to acquire the lock on each Redis instance with the same key and a unique value (e.g., UUID), using a short network timeout.

Measure the time spent acquiring the lock.

If a majority of nodes grant the lock and the elapsed time is less than the lock’s TTL, the lock is successful.

If acquisition fails, release the lock on all nodes.

In short, success requires a majority of nodes to grant the lock and the total acquisition time to be less than the lock’s expiration.

7. Redisson

7.1 Simple implementation

Redisson is a Java client for Redis that provides distributed locks, collections, and objects.

<code>// Acquire distributed lock
RLock lock = redissonClient.getLock("myLock");
try {
    // Wait up to 10 seconds, lock expires after 30 seconds
    boolean locked = lock.tryLock(10, 30, TimeUnit.SECONDS);
    if (locked) {
        System.out.println("Lock acquired, executing business logic...");
    } else {
        System.out.println("Failed to acquire lock...");
    }
} catch (InterruptedException e) {
    e.printStackTrace();
} finally {
    lock.unlock();
    redissonClient.shutdown();
}</code>

Redisson stores lock information in a hash where the field is the thread identifier and the value is the reentrancy count.

7.2 Watchdog mechanism

When a lock is set, Redisson starts a watchdog thread that periodically renews the lock’s TTL (default 30 seconds). This ensures the lock remains valid even if the client experiences temporary network issues or long‑running business logic.

The watchdog checks whether the client still holds the lock and extends the expiration time; if the lock cannot be renewed, it expires and other clients can acquire it.

JavaconcurrencyredisDistributed LockluaRedLock
Top Architect
Written by

Top Architect

Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.

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.