Mastering Redisson: Seamless Distributed Locks in Spring Boot

This tutorial explains what Redisson is, how it extends Redis with powerful distributed data structures and lock mechanisms, and provides step‑by‑step Spring Boot integration, code examples, and detailed testing of re‑entrant, read‑write, and semaphore locks.

macrozheng
macrozheng
macrozheng
Mastering Redisson: Seamless Distributed Locks in Spring Boot

We first look at Redis's official definition of a distributed lock, then introduce Redisson as the Java framework that implements distributed locks on top of Redis.

1. What is Redisson?

If you have used Redis before, Redisson makes working with Redis much easier and more convenient.

Redisson aims to separate concerns so developers can focus on business logic.

It is a Java in‑memory data grid built on top of Redis.

Netty framework : Redisson uses Netty (NIO) as the underlying client, supporting synchronous, asynchronous, reactive, and pipelined command execution, as well as Lua script handling.

Basic data structures : Native Redis structures such as Hash, List, Set, String, Geo, HyperLogLog are wrapped as familiar Java collections like Map, List, Set, Object Bucket, Geospatial Bucket, HyperLogLog.

Distributed data structures : Provides distributed versions of Multimap, LocalCachedMap, SortedSet, ScoredSortedSet, LexSortedSet, Queue, BlockingQueue, BoundedBlockingQueue, Deque, BlockingDeque, DelayedQueue, BloomFilter, AtomicLong, AtomicDouble, BitSet, etc.

Distributed locks : Implements Redis Lock and higher‑level primitives such as MultiLock, ReadWriteLock, FairLock, RedLock, Semaphore, PermitExpirableSemaphore, and CountDownLatch.

Node : A Redisson node can execute remote tasks published to distributed execution or scheduling services.

2. Integrating Redisson

Spring Boot offers two integration methods: programmatic configuration and configuration file. This article demonstrates the programmatic approach.

2.1 Add Maven Dependency

<!-- https://mvnrepository.com/artifact/org.redisson/redisson -->
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.15.5</version>
</dependency>

2.2 Custom Configuration Class

Below is a configuration for a single‑node Redis instance.

@Configuration
public class MyRedissonConfig {
    /**
     * All Redisson usage goes through a RedissonClient object
     */
    @Bean(destroyMethod="shutdown") // called when the service stops
    public RedissonClient redisson() throws IOException {
        // 1. Create Config
        Config config = new Config();
        // 2. Use single server mode
        config.useSingleServer().setAddress("redis://127.0.0.1:6379");
        return Redisson.create(config);
    }
}

2.3 Test Configuration

@Autowired
RedissonClient redissonClient;

@Test
public void TestRedisson() {
    System.out.println(redissonClient);
}

Running the test prints something like org.redisson.Redisson@77f66138.

3. Distributed Re‑entrant Lock

3.1 Re‑entrant Lock Test

Redisson provides RLock which implements java.util.concurrent.locks.Lock and also offers async, reactive, and RxJava2 interfaces.

RLock lock = redisson.getLock("anyLock");
// most common usage
lock.lock();

The demo creates a lock named WuKong-lock, acquires it, prints the thread ID, sleeps for 10 seconds, then releases the lock and returns "test lock ok".

@ResponseBody
@GetMapping("test-lock")
public String TestLock() {
    // 1. Get the lock (same name = same lock)
    RLock lock = redisson.getLock("WuKong-lock");
    // 2. Acquire lock
    lock.lock();
    try {
        System.out.println("Lock acquired, thread ID: " + Thread.currentThread().getId());
        Thread.sleep(10000);
    } catch (Exception e) {
        // TODO
    } finally {
        lock.unlock();
        System.out.println("Finally, lock released, thread ID: " + Thread.currentThread().getId());
    }
    return "test lock ok";
}

Two HTTP requests to the endpoint demonstrate that the second request must wait until the first releases the lock.

The first thread (ID 86) holds the lock for 10 seconds; the second thread blocks and acquires the lock only after the first releases it.

3.1.2 Does the lock release when the service stops?

When the service crashes, Redisson’s watchdog automatically extends the lock’s TTL. By default the watchdog checks every 10 seconds and sets the lock expiration to 30 seconds.

After the service stops, the lock expires after the TTL (30 s) and is automatically released, preventing deadlock.

3.3 Setting Lock Expiration

You can set an explicit lease time so the lock auto‑expires. lock.lock(8, TimeUnit.SECONDS); If the business logic exceeds the lease time, manual unlock will throw an error.

4. "King" Solution

Because Redisson makes distributed locking concise, we call this the "King" solution.

// 1. Get distributed lock
RLock lock = redisson.getLock("lock");
// 2. Acquire lock
lock.lock();
// 3. Business logic
...
// 4. Release lock
lock.unlock();

5. Distributed Read‑Write Lock

Redisson provides RReadWriteLock implementing java.util.concurrent.locks.ReadWriteLock. The read lock is shared, the write lock is exclusive.

RReadWriteLock rwlock = redisson.getReadWriteLock("anyRWLock");
// Acquire read lock
rwlock.readLock().lock();
// Acquire write lock
rwlock.writeLock().lock();

You can also specify a lease time:

// Auto‑unlock after 10 seconds
rwlock.readLock().lock(10, TimeUnit.SECONDS);
rwlock.writeLock().lock(10, TimeUnit.SECONDS);
// Try lock with wait and lease time
boolean ok = rwlock.readLock().tryLock(100, 10, TimeUnit.SECONDS);

6. Distributed Semaphore

Redisson’s RSemaphore mimics java.util.concurrent.Semaphore. It can model scenarios such as limited parking spaces.

/**
 * Acquire a parking spot (total 3 spots)
 */
@ResponseBody
@RequestMapping("park")
public String park() throws InterruptedException {
    RSemaphore park = redisson.getSemaphore("park");
    park.acquire();
    return "OK";
}

/**
 * Release a parking spot
 */
@ResponseBody
@RequestMapping("leave")
public String leave() throws InterruptedException {
    RSemaphore park = redisson.getSemaphore("park");
    park.release();
    return "OK";
}

Initializing the semaphore key park with value 3 in Redis represents three available spots. Subsequent calls to park decrement the count, and calls to leave increment it.

When the count reaches zero, further park requests block until a spot is released.

Other Distributed Locks (brief)

Fair Lock

MultiLock

RedLock

ReadWriteLock

PermitExpirableSemaphore

CountDownLatch

For more details, refer to the official Redisson documentation.

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.

JavaconcurrencyredisSpring Bootdistributed-lockredisson
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

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.