Backend Development 16 min read

A Comprehensive Guide to Redisson Distributed Locks in Java

This article explains Redisson's various distributed lock mechanisms—including watchdog, reentrant lock, multi‑lock, read‑write lock, semaphore, RedLock, and CountDownLatch—detailing their principles, usage patterns, code examples, and best‑practice recommendations for robust backend concurrency control.

Zhuanzhuan Tech
Zhuanzhuan Tech
Zhuanzhuan Tech
A Comprehensive Guide to Redisson Distributed Locks in Java

1. Introduction

Redisson extends Redis with a Swiss‑army‑knife‑like API for Java developers, offering multiple distributed lock types that improve safety and convenience compared to native Redis commands.

2. Watchdog

The watchdog automatically renews a lock before it expires, preventing premature release when business logic runs longer than the default 30‑second timeout.

2‑1. Why a watchdog?

Prevents lock loss if business exceeds the expiration time.

Ensures lock is released if the client crashes.

No need to manually calculate execution time.

2‑2. How it works

Lock acquisition sets a 30‑second TTL.

A background task checks every 10 seconds; if the lock is still held, it extends the TTL.

Lock is released when the business finishes or the client disconnects.

2‑3. Configuring the watchdog

<code>Config config = new Config();
config.setLockWatchdogTimeout(30000L); // milliseconds, default 30 s
RedissonClient redisson = Redisson.create(config);
// Or specify timeout per lock
lock.lock(60, TimeUnit.SECONDS); // watchdog uses 60 s cycle
</code>

3. Reentrant Lock

Provides a distributed version of Java's ReentrantLock , supporting thread‑safety across JVMs, automatic renewal, fair/non‑fair modes, and timeout handling.

3‑1. Features

Thread‑safe across different JVMs.

Watchdog‑based auto‑renewal.

Fair and non‑fair acquisition options.

Timeout to avoid indefinite waiting.

3‑2. Usage examples

Basic (blocking)

<code>RLock lock = redisson.getLock("orderLock");
lock.lock();
try {
    // business logic
} finally {
    lock.unlock();
}
</code>

Try‑lock (non‑blocking)

<code>if (lock.tryLock(3, 30, TimeUnit.SECONDS)) {
    try {
        // business logic
    } finally {
        lock.unlock();
    }
} else {
    log.warn("Failed to acquire lock, retry later");
}
</code>

Async acquisition

<code>RFuture<Void> lockFuture = lock.lockAsync();
lockFuture.whenComplete((res, ex) -> {
    if (ex == null) {
        try {
            // async business
        } finally {
            lock.unlock();
        }
    }
});
</code>

3‑3. Fair lock

<code>RLock fairLock = redisson.getFairLock("myFairLock");
fairLock.lock();
try {
    // business logic
} finally {
    fairLock.unlock();
}
</code>

3‑4. Non‑fair lock

<code>RLock nonFairLock = redisson.getLock("hotItemLock");
if (nonFairLock.tryLock(50, TimeUnit.MILLISECONDS)) {
    try {
        // flash‑sale logic
    } finally {
        nonFairLock.unlock();
    }
}
</code>

3‑5. Reentrant lock internals (Lua pseudocode)

<code>-- Acquire lock
if redis.call('exists', KEYS[1]) == 0 then
    redis.call('hset', KEYS[1], ARGV[2], 1);
    redis.call('pexpire', KEYS[1], ARGV[1]);
    return nil;
end
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
return redis.call('pttl', KEYS[1]);
</code>

4. Multi‑Lock (联锁)

Combines several locks into an atomic "all‑or‑nothing" operation, useful for distributed transactions across multiple resources.

4‑1. Basic usage

<code>RLock lock1 = redisson.getLock("order_lock");
RLock lock2 = redisson.getLock("stock_lock");
RLock lock3 = redisson.getLock("coupon_lock");
RedissonMultiLock multiLock = new RedissonMultiLock(lock1, lock2, lock3);
if (multiLock.tryLock(3, 30, TimeUnit.SECONDS)) {
    // process order, update stock, use coupon
} else {
    log.warn("One resource refused the lock");
}
finally {
    multiLock.unlock();
}
</code>

4‑2. Advanced dynamic construction

<code>List<RLock> locks = resourceIds.stream()
    .map(id -> redisson.getLock("resource_" + id))
    .collect(Collectors.toList());
RedissonMultiLock dynamicLock = new RedissonMultiLock(locks.toArray(new RLock[0]));
</code>

4‑3. Pitfalls

Avoid acquiring locks in different orders (deadlock risk).

Do not mix lock types (fair vs non‑fair) in the same multi‑lock.

Ensure all locks are acquired; otherwise roll back completely.

5. Read‑Write Lock

Allows concurrent reads while writes are exclusive, ideal for read‑heavy scenarios.

<code>RReadWriteLock rwLock = redisson.getReadWriteLock("libraryBook_123");
// Read
rwLock.readLock().lock();
try {
    Book book = getBookFromDB(123);
} finally {
    rwLock.readLock().unlock();
}
// Write
rwLock.writeLock().lock();
try {
    updateBookInDB(123, newVersion);
} finally {
    rwLock.writeLock().unlock();
}
</code>

6. Semaphore

Controls concurrency by limiting the number of permits.

<code>RSemaphore semaphore = redisson.getSemaphore("apiLimit");
semaphore.trySetPermits(10);
semaphore.acquire();
try {
    callLimitedAPI();
} finally {
    semaphore.release();
}
// Non‑blocking try
if (semaphore.tryAcquire()) {
    try { /* work */ } finally { semaphore.release(); }
} else {
    log.warn("System busy, try later");
}
</code>

7. RedLock

Implements the Redlock algorithm across multiple independent Redis nodes to achieve higher availability.

<code>RLock lock1 = redissonClient1.getLock("lock");
RLock lock2 = redissonClient2.getLock("lock");
RLock lock3 = redissonClient3.getLock("lock");
RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);
boolean locked = redLock.tryLock(100, 30, TimeUnit.SECONDS);
if (locked) {
    doCriticalWork();
}
redLock.unlock();
</code>

8. CountDownLatch

Coordinates multiple tasks, blocking until a predefined count reaches zero.

<code>// Coordinator
RCountDownLatch latch = redisson.getCountDownLatch("batchTaskLatch");
latch.trySetCount(5);
// Workers
RCountDownLatch workerLatch = redisson.getCountDownLatch("batchTaskLatch");
workerLatch.countDown();
// Coordinator waits
latch.await();
System.out.println("All tasks completed!");
</code>

9. Summary

Redisson offers a rich set of distributed synchronization primitives—watchdog, reentrant lock, fair/non‑fair locks, multi‑lock, read‑write lock, semaphore, RedLock, and CountDownLatch—each suited to specific backend scenarios; selecting the right primitive and configuring lock granularity and TTL are essential to avoid deadlocks and performance bottlenecks.

JavaConcurrencyRedisRedissonDistributed Locks
Zhuanzhuan Tech
Written by

Zhuanzhuan Tech

A platform for Zhuanzhuan R&D and industry peers to learn and exchange technology, regularly sharing frontline experience and cutting‑edge topics. We welcome practical discussions and sharing; contact waterystone with any questions.

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.