一、分布式锁实现
原理:运用redis string类型存储策略进行实现。同时,设置string过期时间,防止死锁。
**
* 基于redis的分布式锁实现
*
* @author whucke
* @since 2018/12/12 16:47
*/
public abstract class DistributedLock {
private static final String LOCK_SUCCESS = "OK"; //返回结果
private static final Long RELEASE_SUCCESS = 1L;
/**
* 获取分布式锁
*
* @param lockKey 锁名
* @param requestId 锁归属
* @param expireTime 过期时间
* @return
*/
public static boolean getLock(Jedis jedis, String lockKey, String requestId, int expireTime) {
SetParams params = new SetParams()
.nx() //设置key存储策略,如果key存在则存储失败,仅当key不存在是才能成功保存
.px(expireTime); //设置key的过期时间
String ret = jedis.set(lockKey, requestId, params);
if (LOCK_SUCCESS.equals(ret)) {
return true;
}
return false;
}
/**
* 释放锁
*
* @param lockKey 锁名
* @param requestId 锁归属
* @return
*/
public static boolean release(Jedis jedis, String lockKey, String requestId) {
String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
Object ret = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId)); //执行脚本,保持操作原子性
if (RELEASE_SUCCESS.equals(ret)) {
return true;
}
return false;
}
}
二、锁测试
public class DistributedLockTest {
public static void main(String[] args) {
Order order = new Order();
for (int i = 0; i < 100; i++) {
Business business = new Business(order);
business.start();
}
}
/**
* 业务处理类
*/
static class Order {
private final int MAX = 100; //总共
private final String LOCK_KEY = "sale lock key";
private final int EXPIRE_TIME = 10000;
private int remain = 100; //剩余
private final String REDIS_HOST = "127.0.0.1";
/**
* 执行业务操作
*/
public void process() {
String user = "user-" + Thread.currentThread().getId();
//获取锁
Jedis jedis = new Jedis(REDIS_HOST);
boolean lock = false;
int time = 0; //重试次数5次
while (!lock && time < 50) {
lock = DistributedLock.getLock(jedis, LOCK_KEY, user, EXPIRE_TIME);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
time++;
}
if (lock) {
System.out.println("用户:【" + user + "】排队成功,校验库存!");
if (remain > 0) {
int num = MAX - remain + 1; //售出第几个商品
System.out.println("用户:【" + user + "】购买第" + num + "件商品,剩余 " + --remain + " 件商品!");
} else {
System.out.println("该商品已售罄!");
}
//释放锁
boolean release = DistributedLock.release(jedis, LOCK_KEY, user);
if (release) {
System.out.println("用户:【" + user + "】释放资源成功");
} else {
System.out.println("用户:【" + user + "】释放资源失败");
}
} else {
System.out.println("用户:【" + user + "】排队等待中···········");
}
jedis.close();
}
}
/**
* 模拟商品售卖
*/
static class Business extends Thread {
private Order order;
public Business(Order order) {
this.order = order;
}
@Override
public void run() {
order.process();
}
}
}
以上测试方法只能测试开启线程进行锁获取,并发测试可以使用同步屏障CyclicBarrier类来实现,示例:http://ifeve.com/concurrency-cyclicbarrier/
网友评论