Operations 20 min read

Avoid Common Redis Distributed‑Lock Pitfalls and Fix Them

This article explains why naive Redis lock usage can cause non‑atomic operations, forgotten releases, lock‑stealing, re‑entrancy, read‑write contention, segmentation, timeout, master‑slave failures, and offers practical Java/Redisson/Lua solutions to make distributed locks reliable.

Java Backend Technology
Java Backend Technology
Java Backend Technology
Avoid Common Redis Distributed‑Lock Pitfalls and Fix Them

Redis distributed locks are popular for their simplicity and efficiency, but improper use can lead to serious problems.

Non‑Atomic Lock Acquisition

Using SETNX followed by EXPIRE is not atomic; if setting the timeout fails, the lock may never expire and consume memory.

if (jedis.setnx(lockKey, val) == 1) {
    jedis.expire(lockKey, timeout);
}

Forgotten Release

Even if the lock is set atomically with SET (NX, PX), forgetting to release it or releasing it at the wrong time can cause other threads to acquire a stale lock.

String result = jedis.set(lockKey, requestId, "NX", "PX", expireTime);
if ("OK".equals(result)) {
    return true;
}
return false;

Releasing Someone Else's Lock

When a lock expires and another thread acquires it, the original thread may still try to release the lock, deleting a lock it does not own. Use a unique requestId to verify ownership before deletion.

if (jedis.get(lockKey).equals(requestId)) {
    jedis.del(lockKey);
    return true;
}
return false;

Lua Scripts for Atomic Release

Lua ensures the check‑and‑delete operation is atomic.

if redis.call('get', KEYS[1]) == ARGV[1] then
    return redis.call('del', KEYS[1])
else
    return 0
end

Re‑entrant Locks

Standard Redis locks are not re‑entrant. Redisson provides a re‑entrant lock that tracks a counter per requestId.

if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then
    redis.call('hincrby', KEYS[1], ARGV[2], 1);
    redis.call('pexpire', KEYS[1], ARGV[1]);
    return nil;
end

Read‑Write Locks

Redisson implements read‑write locks where multiple readers share the lock while writers obtain exclusive access.

RReadWriteLock rwLock = redisson.getReadWriteLock("readWriteLock");
RLock rLock = rwLock.readLock();
try { rLock.lock(); /* business */ } finally { rLock.unlock(); }

Lock Segmentation

Splitting a large lock into many smaller segments (e.g., 100 shards) reduces contention in high‑traffic scenarios such as flash sales.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Javaconcurrencyredisdistributed-lockLuaredisson
Java Backend Technology
Written by

Java Backend Technology

Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!

0 followers
Reader feedback

How this landed with the community

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.