Distributed Lock Implementation with Redis and Redisson in Spring Boot

This article explains the concept, characteristics, and multiple implementation approaches of distributed locks, focusing on Redis‑based locks and the Redlock algorithm, and provides complete Java code examples using Spring Boot and Redisson for acquiring and releasing locks safely.

Full-Stack Internet Architecture
Full-Stack Internet Architecture
Full-Stack Internet Architecture
Distributed Lock Implementation with Redis and Redisson in Spring Boot

What is a Distributed Lock

In Java, traditional locks such as synchronized and Lock work only within a single JVM, but distributed systems require coordination across multiple servers, which leads to the need for distributed locks.

Definition

A distributed lock is a mechanism that ensures mutually exclusive access to a shared resource across different nodes in a distributed system, preventing data inconsistency.

Characteristics

Mutual exclusion – only one client can hold the lock at any time.

Lock timeout – similar to local locks, to avoid deadlocks.

High availability – lock acquisition and release must remain performant and resilient.

Supports blocking and non‑blocking operations, analogous to ReentrantLock 's lock, tryLock, and tryLock(long timeout).

Implementation Methods

Database lock

Redis‑based distributed lock

Zookeeper‑based distributed lock

For performance reasons, Redis is commonly used, and the Redlock algorithm can further improve reliability.

Code Example – Redis Lock

Lock acquisition uses the Redis atomic command: SET key value [NX|XX] [EX seconds|PX milliseconds] Parameter explanation:

EX seconds – expiration time in seconds.

PX milliseconds – expiration time in milliseconds.

NX – set only if the key does not exist.

XX – set only if the key already exists.

value – a globally unique identifier used to verify ownership when releasing.

/**
 * Acquire lock
 * @return true if lock acquired, false otherwise
 */
public boolean lock(String key, String value, long expireTime) {
    key = prefixKey + key;
    boolean lock = false;
    try {
        lock = redisTemplate.opsForValue().setIfAbsent(key, value, expireTime, TimeUnit.MILLISECONDS);
    } catch (Exception e) {
        e.printStackTrace();
        lock = false;
    }
    if (lock) {
        System.out.println(String.format("%s has obtained the lock, time: %s", Thread.currentThread().getName(), System.currentTimeMillis() / 1000));
    }
    return lock;
}

Lock release should verify ownership, typically using a Lua script:

public boolean unLock(String key, String value) {
    key = prefixKey + key;
    Long result = -1L;
    String luaScript =
            "if redis.call('get', KEYS[1]) == ARGV[1] then " +
            "  return redis.call('del', KEYS[1]) " +
            "else " +
            "  return 0 " +
            "end";
    DefaultRedisScript<Long> redisScript = new DefaultRedisScript(luaScript, Long.class);
    try {
        result = (Long) redisTemplate.execute(redisScript, Lists.list(key), value);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return result == 1 ? true : false;
}
In a master‑slave setup, a race condition can occur if the master fails after granting a lock but before replicating it, leading to a "safe failure" scenario.

Redisson Implementation of Distributed Lock

Antirez proposed the Redlock algorithm to handle Redis node failures. The algorithm attempts to acquire the lock on multiple independent Redis instances; if a majority (N/2+1) succeed within the lock’s TTL, the lock is considered acquired.

Execution Steps

Client records the current time.

Client sends SET commands with NX and EX/PX to N Redis instances sequentially.

After all attempts, the client measures total elapsed time and checks two conditions:

At least a majority of instances granted the lock.

Total elapsed time is less than the lock’s TTL.

If both conditions are met, the client recalculates the remaining TTL and proceeds; otherwise it releases any acquired locks.

Redisson Code Example

Add the Redisson dependency:

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.9.1</version>
</dependency>

Configure a Sentinel‑based client:

Config config = new Config();
config.useSentinelServers()
      .addSentinelAddress("127.0.0.1:6479", "127.0.0.1:6489")
      .setMasterName("master")
      .setPassword("password")
      .setDatabase(0);
RedissonClient redisson = Redisson.create(config);

Acquire and release the lock:

RLock lock = redisson.getLock("test_lock");
try {
    boolean isLock = lock.tryLock();
    if (isLock) {
        // simulate business logic
        doBusiness();
    }
} catch (Exception e) {
    // handle exception
} finally {
    lock.unlock();
}

Project Source Code

https://github.com/aalansehaiyang/spring-boot-bulking
Module: spring-boot-bulking-redis-lock

For further reading, the article also recommends related posts on Redis cache design, architecture principles, and Spring Boot Kafka integration.

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.

BackendJavaconcurrencyredisSpring Bootdistributed-lockredisson
Full-Stack Internet Architecture
Written by

Full-Stack Internet Architecture

Introducing full-stack Internet architecture technologies centered on Java

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.