SpringBoot Redis Distributed Lock: Simulating High‑Concurrency Order Grab
This tutorial explains how to implement a Redis distributed lock with SpringBoot and Jedis, covering lock creation using SETNX, expiration handling, safe unlocking via Lua scripts, and a 100,000‑user parallelStream simulation of a limited‑stock order‑grab scenario, complete with code samples and results.
Overview
This article demonstrates how to implement a Redis‑based distributed lock in a Spring Boot application using the Jedis client. The lock is applied to a high‑concurrency “order‑grab” scenario where many virtual users compete for a limited inventory.
Project Setup
Add the Jedis dependency to pom.xml:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>Lock Acquisition (SETNX)
Use SET with the NX (set if not exists) and PX (expire in milliseconds) options to create the lock atomically. The method returns true only when the key is set successfully.
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;
}Expose the method via a REST endpoint:
@GetMapping("/setnx/{key}/{val}")
public boolean setnx(@PathVariable String key, @PathVariable String val) {
return jedisCom.setnx(key, val);
}Lock Release (Safe Unlock)
To avoid deleting a lock owned by another client, execute a Lua script that checks the stored value before deleting:
public int delnx(String key, String val) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
if (jedis == null) return 0;
String script = "if redis.call('get','" + key + "')=='" + val + "' then "
+ "return redis.call('del','" + key + "') else return 0 end";
return Integer.valueOf(jedis.eval(script).toString());
} catch (Exception ex) {
// handle exception
} finally {
if (jedis != null) jedis.close();
}
return 0;
}REST wrapper for unlocking:
@GetMapping("/delnx/{key}/{val}")
public int delnx(@PathVariable String key, @PathVariable String val) {
return jedisCom.delnx(key, val);
}Simulation of 100,000 Users Competing for 10 Items
The demo creates 100,000 virtual users ( 神牛‑0 … 神牛‑99999) and a shared inventory of 10 items. Java parallel streams emulate concurrent requests.
// shared state
private long inventory = 0;
private final String productKey = "computer_key";
private final int lockTimeoutMs = 30 * 1000;
@GetMapping("/qiangdan")
public List<String> qiangdan() {
List<String> successUsers = new ArrayList<>();
List<String> users = new ArrayList<>();
IntStream.range(0, 100000).parallel().forEach(i -> users.add("神牛-" + i));
inventory = 10; // only 10 items
users.parallelStream().forEach(u -> {
String result = tryGrab(u);
if (!StringUtils.isEmpty(result)) successUsers.add(result);
});
return successUsers;
}
private String tryGrab(String user) {
long start = System.currentTimeMillis();
while (start + lockTimeoutMs >= System.currentTimeMillis()) {
if (inventory <= 0) break;
if (jedisCom.setnx(productKey, user)) {
try {
if (inventory <= 0) break;
// simulate order processing
TimeUnit.SECONDS.sleep(1);
inventory--;
return user + "抢单成功,所剩库存:" + inventory;
} finally {
jedisCom.delnx(productKey, user);
}
}
}
return "";
}Key points of the algorithm:
Parallel streams generate a large number of concurrent users.
Each user repeatedly attempts to acquire the lock within a 30‑second window.
Lock acquisition uses setnx; release uses the Lua‑based delnx to guarantee ownership.
Inventory is checked both before and after acquiring the lock to prevent overselling.
Result Observation
Running /qiangdan produces logs that show which user obtained the lock, succeeded in ordering, and released the lock. The total number of successful orders never exceeds the initial inventory of 10, confirming correct exclusive access.
Conclusion
The example provides a concrete pattern for implementing a Redis distributed lock in Spring Boot, handling lock expiration, ensuring safe unlocking with an atomic Lua script, and stress‑testing the solution under massive concurrency using Java parallel streams. This approach is applicable to flash‑sale, ticket‑booking, or any scenario that requires exclusive access to a shared resource.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Architect Essentials
Committed to sharing quality articles and tutorials to help Java programmers progress from junior to mid-level to senior architect. We curate high-quality learning resources, interview questions, videos, and projects from across the internet to help you systematically improve your Java architecture skills. Follow and reply '1024' to get Java programming resources. Learn together, grow together.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
