java 从零实现属于你的 redis 分布式锁( 二 )

< endMills) {result = tryLock(key);if(result) {return true;}// 等待 10mswait.wait(TimeUnit.MILLISECONDS, 10);}return false;}@Overridepublic synchronized boolean tryLock(long time, TimeUnit unit) throws InterruptedException {return tryLock(time, unit, LockRedisConst.DEFAULT_KEY);}@Overridepublic Condition newCondition() {throw new UnsupportedOperationException();}}最核心的实际上是 public boolean tryLock(long time, TimeUnit unit, String key) throws InterruptedException 方法 。
这个方法会调用 this.tryLock(key) 获取锁 , 如果成功 , 直接返回;如果不成功 , 则循环等待 。
【java 从零实现属于你的 redis 分布式锁】这里设置了超时时间 , 如果超时 , 则直接返回 true 。
redis 锁实现我们实现的 redis 分布锁 , 继承自上面的抽象类 。
package com.github.houbb.lock.redis.core;import com.github.houbb.heaven.util.lang.StringUtil;import com.github.houbb.id.api.Id;import com.github.houbb.id.core.util.IdThreadLocalHelper;import com.github.houbb.lock.redis.constant.LockRedisConst;import com.github.houbb.lock.redis.exception.LockRedisException;import com.github.houbb.lock.redis.support.operator.IOperator;import com.github.houbb.wait.api.IWait;/** * 这里是基于 redis 实现 * * 实际上也可以基于 zk/数据库等实现 。* * @author binbin.hou * @since 0.0.1 */public class LockRedis extends AbstractLockRedis {/*** redis 操作实现* @since 0.0.1*/private final IOperator redisOperator;/*** 主键标识* @since 0.0.1*/private final Id id;public LockRedis(IWait wait, IOperator redisOperator, Id id) {super(wait);this.redisOperator = redisOperator;this.id = id;}@Overridepublic boolean tryLock(String key) {final String requestId = id.id();IdThreadLocalHelper.put(requestId);return redisOperator.lock(key, requestId, LockRedisConst.DEFAULT_EXPIRE_MILLS);}@Overridepublic void unlock(String key) {final String requestId = IdThreadLocalHelper.get();if(StringUtil.isEmpty(requestId)) {String threadName = Thread.currentThread().getName();throw new LockRedisException("Thread " + threadName +" not contains requestId");}boolean unlock = redisOperator.unlock(key, requestId);if(!unlock) {throw new LockRedisException("Unlock key " + key + " result is failed!");}}}这里就是 redis 锁的核心实现了 , 如果不太理解 , 建议回顾一下原理篇:
redis 分布式锁原理详解
加锁加锁部分 , 这里会生成一个 id 标识 , 用于区分当前操作者 。
为了安全也设置了默认的超时时间 。
当然这里是为了简化调用者的使用成本 , 开发在使用的时候只需要关心自己要加锁的 key 即可 。
当然 , 甚至连加锁的 key 都可以进一步抽象掉 , 比如封装 @DistributedLock 放在方法上 , 即可实现分布式锁 。 这个后续有时间可以拓展 , 原理也不难 。
解锁解锁的时候 , 就会获取当前进程的持有标识 。
凭借当前线程持有的 id 标识 , 去解锁 。
IOperator我们对 redis 的操作进行了抽象 , 为什么抽象呢?
因为 redis 服务种类实际很多 , 可以是 redis 单点 , 集群 , 主从 , 哨兵 。
连接的客户端也可以很多 , jedis , spring redisTemplate, codis, redisson 等等 。
这里为了后期拓展方便 , 就对操作进行了抽象 。
接口定义接口如下:
package com.github.houbb.lock.redis.support.operator;/** * Redis 客户端 * @author binbin.hou * @since 0.0.1 */public interface IOperator {/*** 尝试获取分布式锁** @param lockKey锁* @param requestId请求标识* @param expireTimeMills 超期时间* @return 是否获取成功* @since 0.0.1*/boolean lock(String lockKey, String requestId, int expireTimeMills);/*** 解锁* @param lockKey 锁 key* @param requestId 请求标识* @return 结果* @since 0.0.1*/boolean unlock(String lockKey, String requestId);}