由于前几个月本人用到了一些分布式锁的案例,特地整理出来,和大家分享,该代码直接分享出来,直接可以用,大家有问题可以留言,有优化的地方也直接提出来,大家共同进步。
zoopkeeper锁:https://blog.csdn.net/lyz812672598/article/details/84994967
如果需要转载,请贴明出处,谢谢大家!
/**
* <p>redis分布式锁</p>
*
* @author liyz
* @version 1.0.0
* @date 2018/12/13 0013 15:04
*/
@Slf4j
public final class RedisLock {
/**
* redis实例
*/
private RedisTemplate<String, Object> redisTemplate;
/**
* set参数,等效于setNX
*/
private static final String NX = "NX";
/**
* set参数,以s(秒)为单位设置过期时间
*/
public static final String EX = "EX";
/**
* set参数,以ms(毫秒)为单位设置过期时间
*/
public static final String PX = "PX";
/**
* 调用set方法返回值
*/
public static final String OK = "OK";
/**
* lockKey的结束符
*/
public static final String LOCK_TAILED = "_lock";
/**
* 默认set超时时间(ms)
*/
private static final long DEFAULT_TIME_OUT = 100;
/**
* 默认锁的有效时间(s)
*/
private static final int DEFUALT_EXPIRE = 60;
/**
* 解锁LUA脚本
*/
public static final String DEFAULT_UNLOCK_LUA;
static {
StringBuilder sb = new StringBuilder();
sb.append("if redis.call(\"get\",KEYS[1]) == ARGV[1] ");
sb.append("then ");
sb.append(" return redis.call(\"del\",KEYS[1]) ");
sb.append("else ");
sb.append(" return 0 ");
sb.append("end ");
DEFAULT_UNLOCK_LUA = sb.toString();
}
/**
* key
*/
private String lockKey;
/**
* 所对应的值
*/
private ThreadLocal<String> lockFlag = new ThreadLocal<>();
/**
* 锁的有效期
*/
private int expire;
/**
* 获取锁的超时时间
*/
private long timeOut;
/**
* 锁标记
*/
private volatile boolean locked = false;
private final Random random = new Random();
/**
* 构造函数
*
* @param redisTemplate
* @param lockKey
*/
public RedisLock(RedisTemplate<String, Object> redisTemplate, String lockKey) {
this(redisTemplate, lockKey, DEFUALT_EXPIRE);
}
public RedisLock(RedisTemplate<String, Object> redisTemplate, String lockKey, int expire) {
this(redisTemplate, lockKey, expire, DEFAULT_TIME_OUT);
}
public RedisLock(RedisTemplate<String, Object> redisTemplate, String lockKey, long timeOut) {
this(redisTemplate, lockKey, DEFUALT_EXPIRE, timeOut);
}
public RedisLock(RedisTemplate<String, Object> redisTemplate, String lockKey, int expire, long timeOut) {
this.redisTemplate = redisTemplate;
this.lockKey = lockKey + LOCK_TAILED;
this.expire = expire;
this.timeOut = timeOut;
}
/**
* 尝试获取锁,如果没有成功,在超时时间内一直重试
*
* @return
*/
public boolean tryLock() {
//超时时间 纳秒
long timeOut = this.timeOut * 1000000;
long now = System.nanoTime();
while ((System.nanoTime() - now) < timeOut) {
if (OK.equalsIgnoreCase(this.set(lockKey, expire))) {
locked = true;
return locked;
}
//休眠一小下
seleep(10, 50000);
}
return locked;
}
/**
* 获取锁,不管成功失败,立马返回结果
*
* @return
*/
public boolean lock() {
locked = OK.equalsIgnoreCase(this.set(lockKey, expire));
return locked;
}
/**
* 获取锁,直到成功为止
* 慎用!!!!!!
*
* @return
*/
public boolean blockLock() {
for (;;) {
if (OK.equalsIgnoreCase(this.set(lockKey, expire))) {
locked = true;
return locked;
}
//休眠一小下
seleep(10, 50000);
}
}
/**
* 解锁
* <p>使用LUA脚本删除key,可以防止过期的客户端误删除key的情况,而不是使用delete命令删除key</p>
*
* @return
*/
public boolean unLock() {
if (locked) {
Boolean result = (Boolean) redisTemplate.execute(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
Object nativeConnection = connection.getNativeConnection();
Long result = 0L;
List<String> keys = new ArrayList<>();
keys.add(lockKey);
List<String> values = new ArrayList<>();
values.add(lockFlag.get());
// 集群模式
if (nativeConnection instanceof JedisCluster) {
result = (Long) ((JedisCluster) nativeConnection).eval(DEFAULT_UNLOCK_LUA, keys, values);
}
// 单机模式
if (nativeConnection instanceof Jedis) {
result = (Long) ((Jedis) nativeConnection).eval(DEFAULT_UNLOCK_LUA, keys, values);
}
if (result == 0) {
log.info("Redis分布式锁,解锁{}失败!解锁时间:{}", lockKey, System.currentTimeMillis());
}
locked = result == 0;
return result == 1;
}
});
return result == null ? false : result;
}
return true;
}
/**
* 休眠
*
* @param millis
* @param nanos
*/
private void seleep(int millis, int nanos) {
try {
Thread.sleep(millis, random.nextInt(nanos));
} catch (Exception e) {
log.info("***************获取锁休眠失败:{}", e.getMessage());
}
}
/**
* set key
*
* @param lockKey
* @param expire
* @return ok:success; nil:fail
*/
private String set(final String lockKey, final int expire) {
if (org.apache.commons.lang3.StringUtils.isBlank(lockKey)) {
throw new IllegalArgumentException();
}
return (String) redisTemplate.execute(new RedisCallback<String>() {
@Override
public String doInRedis(RedisConnection connection) throws DataAccessException {
Object nativeConnection = connection.getNativeConnection();
String result = null;
if (nativeConnection instanceof JedisCommands) {
String uuid = UUID.randomUUID().toString();
lockFlag.set(uuid);
result = ((JedisCommands) nativeConnection).set(lockKey, uuid, NX, EX, expire);
}
if (!StringUtils.isEmpty(result)) {
log.info("获取锁{}的时间:{}", lockKey, System.currentTimeMillis());
}
return result;
}
});
}
/**
* 判断是否获得锁
*
* @return
*/
public boolean isLock() {
return locked;
}
public boolean isLock(RedisLock redisLock) {
return redisLock.isLock();
}
}
就是这么暴力,直接可以用