Java基于Redis的分布式锁
分布式锁,其实最终还是要保证锁(数据)的一致性,说到数据一致性,基于ZK,ETCD数据一致性中间件做分数是锁,才是王道。但是Redis也能满足最基本的需求。
参考:
https://www.cnblogs.com/technologykai/p/8658689.html
https://www.cnblogs.com/rgcLOVEyaya/p/RGC_LOVE_YAYA_1003days.html
@Component public class RedisLockManager implements Lock { Logger logger = LoggerFactory.getLogger(RedisLockManager.class); @Autowired RedisTool redisManager; /** * 请求锁的超时时间(ms) */ private final long TIME_OUT = 30000; /** * 锁的有效时间(毫秒) */ private long expire = 15000; private String key; private String value; private volatile boolean isLocked = false; public void setKey(String key) { this.key = key; } public void setValue(String value) { this.value = value; } @Override public void lock() { //系统当前时间,毫秒 long nowTime = System.nanoTime(); //请求锁超时时间,毫秒 long timeout = TIME_OUT * 1000000; ThreadLocalRandom random = ThreadLocalRandom.current(); try { while ((System.nanoTime() - nowTime) < timeout) { boolean flag = redisManager.tryGetDistributedLock(this.key, this.value, this.expire); if (flag) { isLocked = true; //上锁成功结束请求 break; } Thread.sleep(3, random.nextInt(500)); } } catch (Exception e) { isLocked = false; logger.error(e.getMessage(), e); } } @Override public void unlock() { //释放锁 //不管请求锁是否成功,只要已经上锁,客户端都会进行释放锁的操作 if (isLocked) { redisManager.releaseDistributedLock(this.key, this.value); this.isLocked = false; } } @Override public void lockInterruptibly() { // TODO Auto-generated method stub } @Override public boolean tryLock() { // TODO Auto-generated method stub return false; } @Override public boolean tryLock(long time, TimeUnit unit) { this.expire = unit.toMillis(time); this.lock(); return this.isLocked; } @Override public Condition newCondition() { // TODO Auto-generated method stub return null; } }
@Component
public class RedisTool {
@Autwire
Jedis jedis;
private final String LOCK_SUCCESS = "OK"; private final String SET_IF_NOT_EXIST = "NX"; private final String SET_WITH_EXPIRE_TIME = "PX"; /** * 尝试获取分布式锁 * @param jedis Redis客户端 * @param lockKey 锁 * @param requestId 请求标识 * @param expireTime 超期时间 * @return 是否获取成功 */ public boolean tryGetDistributedLock(String lockKey, String requestId, int expireTime) { String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime); if (LOCK_SUCCESS.equals(result)) { return true; } return false; } private final Long RELEASE_SUCCESS = 1L; /** * 释放分布式锁 * @param jedis Redis客户端 * @param lockKey 锁 * @param requestId 请求标识 * @return 是否释放成功 */ public boolean releaseDistributedLock(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 result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId)); if (RELEASE_SUCCESS.equals(result)) { return true; } return false; } }