https://blog.youkuaiyun.com/yb223731/article/details/90349502
首先,set()加入了NX参数,可以保证如果已有key存在,则函数不会调用成功,也就是只有一个客户端能持有锁,满足互斥性。其次,由于我们对锁设置了过期时间,即使锁的持有者后续发生崩溃而没有解锁,锁也会因为到了过期时间而自动解锁(即key被删除),不会发生死锁。最后,因为我们将value赋值为requestId,代表加锁的客户端请求标识,那么在客户端在解锁的时候就可以进行校验是否是同一个客户端。
public class DistributedLock
{
private static final String LOCK_SUCCESS = "OK";
private static final String SET_IF_NOT_EXIST = "NX";
private static final String SET_WITH_EXPIRE_TIME = "PX";
/**
* 尝试获取分布式锁
* @param redisTemplate Redis客户端
* @param lockKey 锁
* @param requestId 请求标识
* @param expireTime 超期时间 传入参数单位秒 如:60 即60秒
* @return 是否获取成功
*/
public static boolean getDistributedLock(RedisClientTemplate redisTemplate, String lockKey, String requestId,
int expireTime)
{
String result = redisTemplate.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime * 1000);
if (LOCK_SUCCESS.equals(result))
{
return true;
}
return false;
}
/**
*
* @方法描述: 释放分布式锁
* @创建时间: 2019年7月10日 下午5:37:28
* @param redisTemplate
* @param lockKey
* @param requestId
* @return boolean
*/
public static boolean releaseDistributedLock(RedisClientTemplate redisTemplate, String lockKey, String requestId)
{
// if redis.call('get','lockKey')=='requestId' then return
// redis.call('del','lockKey') else return 0 end
StringBuilder sbScript = new StringBuilder();
sbScript.append("if redis.call('get','").append(lockKey).append("')").append("=='").append(requestId)
.append("'").append(" then ").append(" return redis.call('del','").append(lockKey).append("')")
.append(" else ").append(" return 0").append(" end");
return Integer.valueOf(redisTemplate.eval(sbScript.toString()).toString()) > 0;
}
}
String requestId = UUID.randomUUID().toString();
boolean flag = DistributedLock.getDistributedLock(redisClientTemplate, key, requestId,
PropertiesUtil.getExpireSeconds());
if (flag)
{
try
{
// 业务逻辑
return true;
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
DistributedLock.releaseDistributedLock(redisClientTemplate, key, requestId);
}
}