Implementing Distributed Locks with Redis and Redisson in Java

The article explains why Java's synchronized lock cannot be used for distributed scenarios, demonstrates how to build a Redis‑based distributed lock with setIfAbsent, discusses pitfalls such as server crashes and lock expiration, and presents robust solutions including atomic expiration, thread‑ID verification, lock renewal, and Redisson usage.

Top Architect
Top Architect
Top Architect
Implementing Distributed Locks with Redis and Redisson in Java

In distributed systems a JVM‑level synchronized lock cannot guarantee mutual exclusion across multiple instances, so a Redis‑based lock is needed.

Using setIfAbsent (SETNX) you can attempt to acquire a lock by storing a key only if it does not already exist; if the call returns false the lock acquisition fails.

Simple acquisition without expiration can lead to deadlocks when a server crashes before releasing the lock. Adding an explicit timeout with expire mitigates this, but the timeout and the lock acquisition must be atomic to avoid a window where the lock is held without an expiration.

Redis provides an atomic operation that sets the value and its TTL in a single call:

Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "product_001_lock", 30, TimeUnit.SECONDS);

To prevent a thread that timed out from releasing another thread's lock, store a unique client identifier with the lock and verify it before deletion:

String clientId = UUID.randomUUID().toString();
Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, clientId, 30, TimeUnit.SECONDS);
...finally {
    if (clientId.equals(stringRedisTemplate.opsForValue().get(lockKey))) {
        stringRedisTemplate.delete(lockKey);
    }
}

For more advanced scenarios, Redisson offers a high‑level API. The lock object is obtained with redisson.getLock(lockKey) and can be locked, used, and safely unlocked, while Redisson handles automatic lock renewal (watch‑dog) behind the scenes.

RLock redissonLock = redisson.getLock(lockKey);
try {
    redissonLock.lock();
    // critical section
} finally {
    redissonLock.unlock();
}

In summary, a correct distributed lock implementation must ensure mutual exclusion, avoid deadlocks through expiration, bind lock and unlock to the same logical thread (or client ID), and preferably use atomic operations or libraries like Redisson that encapsulate these concerns.

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.

Javaconcurrencyredisredisson
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

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.