← All articles
Backend1 min read

Distributed Locking with Redis

When multiple instances race for the same resource, you need a lock they all respect. Redis provides a simple, fast distributed lock primitive.

S

Swapnika Voora

Author

In a single process, a synchronized block is enough. Across many instances, you need a lock that lives outside any one JVM. Redis, with an atomic set-if- absent and an expiry, is a popular choice for this.

Acquire with SET NX PX

The key trick is atomicity: set the lock only if absent, with a TTL so a crashed holder can't lock forever. Store a unique token to prove ownership on release.

RedisLock.java
public boolean tryLock(String key, String token, Duration ttl) {
    Boolean acquired = redis.opsForValue()
        .setIfAbsent(key, token, ttl);
    return Boolean.TRUE.equals(acquired);
}

Release safely with a script

Never delete the key unconditionally — you might delete a lock another instance already acquired after yours expired. Use a Lua script that checks the token first, atomically.

unlock.java
private static final String UNLOCK =
    "if redis.call('get', KEYS[1]) == ARGV[1] " +
    "then return redis.call('del', KEYS[1]) else return 0 end";
 
public void unlock(String key, String token) {
    redis.execute(RedisScript.of(UNLOCK, Long.class),
        List.of(key), token);
}

Use it around critical work

JobRunner.java
String token = UUID.randomUUID().toString();
if (lock.tryLock("job:nightly", token, Duration.ofMinutes(5))) {
    try {
        runNightlyJob();
    } finally {
        lock.unlock("job:nightly", token);
    }
}

Takeaways

  • SET key value NX PX ttl acquires atomically with automatic expiry.
  • Always release with a token check so you can't free someone else's lock.
  • The TTL is a safety valve — size it larger than the worst-case work time.

For stronger guarantees under network partitions, look at the Redlock algorithm or a consensus system like ZooKeeper.

#java#spring-boot#redis#concurrency

More in Backend