Mastering Redis Distributed Locks with Jedis: From Basics to High-Concurrency Simulation

This article explains how to implement a Redis distributed lock using Jedis in Java, covering lock creation with SETNX, expiration handling, lock deletion via Lua scripts, and a high-concurrency flash‑sale simulation with 100,000 parallel users.

macrozheng
macrozheng
macrozheng
Mastering Redis Distributed Locks with Jedis: From Basics to High-Concurrency Simulation

This article explains how to implement a Redis distributed lock using Jedis in Java, covering lock creation with SETNX, lock expiration, lock deletion, and a high‑concurrency “flash‑sale” simulation with 100,000 parallel users.

Jedis NX lock creation

How to delete a lock

Simulate 100k users grabbing orders

Jedis NX lock generation

First, add the Jedis dependency to the Maven pom:

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency>

Key points for distributed lock:

Lock creation strategy: Using SETNX ensures only the first client succeeds, preventing multiple clients from acquiring the same lock.

Lock expiration: Setting an expiration time avoids deadlocks when a client fails to release the lock.

Example of SETNX implementation:

public boolean setnx(String key, String val) {
    Jedis jedis = null;
    try {
        jedis = jedisPool.getResource();
        if (jedis == null) {
            return false;
        }
        return jedis.set(key, val, "NX", "PX", 1000 * 60).equalsIgnoreCase("ok");
    } catch (Exception ex) {
        // handle exception
    } finally {
        if (jedis != null) {
            jedis.close();
        }
    }
    return false;
}

Explanation of SET parameters:

NX – set only if the key does not exist.

PX – set expiration time in milliseconds.

API endpoint to call the lock:

@GetMapping("/setnx/{key}/{val}")
public boolean setnx(@PathVariable String key, @PathVariable String val) {
    return jedisCom.setnx(key, val);
}

Lock deletion uses a Lua script to ensure the lock is removed only by its owner:

public int delnx(String key, String val) {
    Jedis jedis = null;
    try {
        jedis = jedisPool.getResource();
        if (jedis == null) {
            return 0;
        }
        StringBuilder sbScript = new StringBuilder();
        sbScript.append("if redis.call('get','").append(key).append("')"
                .append("=='").append(val).append("' then ")
                .append("    return redis.call('del','").append(key).append("')"
                .append(" else ")
                .append("    return 0"
                ).append(" end");
        return Integer.valueOf(jedis.eval(sbScript.toString()).toString());
    } catch (Exception ex) {
        // handle exception
    } finally {
        if (jedis != null) {
            jedis.close();
        }
    }
    return 0;
}

API endpoint for lock deletion:

@GetMapping("/delnx/{key}/{val}")
public int delnx(@PathVariable String key, @PathVariable String val) {
    return jedisCom.delnx(key, val);
}

Simulating 100k concurrent order grabs

The simulation initializes a stock of 10 items and creates 100,000 user identifiers, then uses parallelStream() to let each user attempt to acquire the lock, decrement stock, and release the lock.

private String qiang(String b) {
    long startTime = System.currentTimeMillis();
    while ((startTime + timeout) >= System.currentTimeMillis()) {
        if (nKuCuen <= 0) {
            break;
        }
        if (jedisCom.setnx(shangpingKey, b)) {
            logger.info("用户{}拿到锁...", b);
            try {
                if (nKuCuen <= 0) {
                    break;
                }
                // simulate order processing time
                TimeUnit.SECONDS.sleep(1);
                nKuCuen -= 1;
                logger.info("用户{}抢单成功跳出...所剩库存:{}", b, nKuCuen);
                return b + "抢单成功,所剩库存:" + nKuCuen;
            } finally {
                logger.info("用户{}释放锁...", b);
                jedisCom.delnx(shangpingKey, b);
            }
        } else {
            // lock not acquired, continue trying within timeout
        }
    }
    return "";
}

Key logic includes:

ParallelStream for concurrent users.

Timeout loop to keep trying within a defined period.

Stock checks before and after acquiring the lock.

Use jedisCom.setnx to obtain the lock and jedisCom.delnx to release it.

Log screenshots demonstrate that only one request succeeds per lock acquisition and show the final list of successful purchasers.

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.

javaconcurrencyredisJedisSpring Boot
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.