Implementing Redis Distributed Locks with Jedis and Simulating High‑Concurrency Order Grabbing in Java
This article explains how to use Redis as a distributed lock via Jedis in Java, covering lock creation with SETNX/NX/PX, lock deletion with Lua scripts, and a complete 100,000‑user concurrency simulation that demonstrates inventory control and lock management for flash‑sale scenarios.
The article introduces Redis distributed locks, a common interview topic, and demonstrates their usage in a simulated flash‑sale (order‑grabbing) scenario using Java and the Jedis client.
Dependency
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>Lock creation strategy
Redis keys can be overwritten, so a simple SETNX (or SET … NX PX) is used: the first client that sets the key succeeds, subsequent attempts fail, ensuring only one holder at a time. An expiration (PX) is added to avoid deadlocks.
Java method for acquiring the lock
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) {
} finally {
if (jedis != null) {
jedis.close();
}
}
return false;
}The method uses the NX flag (set only if the key does not exist) and PX to specify a millisecond expiration.
REST endpoint to call the lock method
@GetMapping("/setnx/{key}/{val}")
public boolean setnx(@PathVariable String key, @PathVariable String val) {
return jedisCom.setnx(key, val);
}Lock deletion
Because the lock has an expiration, it is still advisable to delete it explicitly when the business operation finishes. The deletion is performed with a Lua script that checks the stored value before removing the key, guaranteeing atomicity.
public int delnx(String key, String val) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
if (jedis == null) {
return 0;
}
// if redis.call('get','orderkey')=='1111' then return redis.call('del','orderkey') else return 0 end
StringBuilder sbScript = new StringBuilder();
sbScript.append("if redis.call('get','").append(key).append("')"
.append("=='").append(val).append("'"
).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) {
} finally {
if (jedis != null) {
jedis.close();
}
}
return 0;
}REST endpoint for lock removal
@GetMapping("/delnx/{key}/{val}")
public int delnx(@PathVariable String key, @PathVariable String val) {
return jedisCom.delnx(key, val);
}Simulation of 100,000 concurrent users
Ten‑thousand users are generated, inventory is set to 10, and a parallel stream simulates the rush. Each user repeatedly tries to acquire the lock within a 30‑second timeout, checks inventory, creates an order, decrements stock, and finally releases the lock.
// total inventory
private long nKuCuen = 0;
// product key name
private String shangpingKey = "computer_key";
// lock timeout (seconds)
private int timeout = 30 * 1000;
@GetMapping("/qiangdan")
public List<String> qiangdan() {
List<String> shopUsers = new ArrayList<>();
List<String> users = new ArrayList<>();
IntStream.range(0, 100000).parallel().forEach(b -> users.add("神牛-" + b));
nKuCuen = 10;
users.parallelStream().forEach(b -> {
String shopUser = qiang(b);
if (!StringUtils.isEmpty(shopUser)) {
shopUsers.add(shopUser);
}
});
return shopUsers;
}The core purchase logic:
/**
* Simulate a single user trying to grab an order.
*/
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 creation delay
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
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 "";
}The logs show which users obtained the lock, succeeded in ordering, and released the lock. The final result lists all users who successfully purchased the limited‑stock item.
At the end of the article, the author offers a set of interview questions from major tech companies and mentions a promotional “gift” for readers who reply with specific keywords.
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.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn 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.
