release branch 0.0.3
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>lock</artifactId>
|
||||
<groupId>com.github.houbb</groupId>
|
||||
<version>0.0.3-SNAPSHOT</version>
|
||||
<version>0.0.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -37,11 +37,7 @@
|
||||
<artifactId>log-integration</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--============================== OTHER ==============================-->
|
||||
<dependency>
|
||||
<groupId>redis.clients</groupId>
|
||||
<artifactId>jedis</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
package com.github.houbb.lock.redis.bs;
|
||||
|
||||
import com.github.houbb.id.api.Id;
|
||||
import com.github.houbb.id.core.core.Ids;
|
||||
import com.github.houbb.lock.api.core.ILock;
|
||||
import com.github.houbb.lock.redis.core.LockRedis;
|
||||
import com.github.houbb.lock.redis.support.operator.IOperator;
|
||||
import com.github.houbb.wait.api.IWait;
|
||||
import com.github.houbb.wait.core.Waits;
|
||||
|
||||
/**
|
||||
* 引导类
|
||||
* @author binbin.hou
|
||||
* @since 0.0.1
|
||||
*/
|
||||
public final class LockRedisBs {
|
||||
|
||||
private LockRedisBs(){}
|
||||
|
||||
/**
|
||||
* 等待实现
|
||||
* @since 0.0.1
|
||||
*/
|
||||
private IWait wait = Waits.threadSleep();
|
||||
|
||||
/**
|
||||
* 等待实现
|
||||
* @since 0.0.1
|
||||
*/
|
||||
private Id id = Ids.uuid32();
|
||||
|
||||
/**
|
||||
* 操作类
|
||||
* @since 0.0.1
|
||||
*/
|
||||
private IOperator operator;
|
||||
|
||||
/**
|
||||
* 新建对象实例
|
||||
* @return 对象实例
|
||||
* @since 0.0.1
|
||||
*/
|
||||
public static LockRedisBs newInstance() {
|
||||
return new LockRedisBs();
|
||||
}
|
||||
|
||||
public LockRedisBs wait(IWait wait) {
|
||||
this.wait = wait;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LockRedisBs id(Id id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LockRedisBs operator(IOperator operator) {
|
||||
this.operator = operator;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建锁
|
||||
* @return 锁
|
||||
* @since 0.0.1
|
||||
*/
|
||||
public ILock lock() {
|
||||
return new LockRedis(wait, operator, id);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.github.houbb.lock.redis.constant;
|
||||
|
||||
/**
|
||||
* 通用锁常量
|
||||
*
|
||||
* @author binbin.hou
|
||||
* @since 0.0.3
|
||||
*/
|
||||
public final class LockConst {
|
||||
|
||||
private LockConst() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认的失效时间
|
||||
*
|
||||
* 暂时定为 30min
|
||||
* @since 0.0.1
|
||||
*/
|
||||
public static final int DEFAULT_EXPIRE_MILLS = 1000 * 60 * 30;
|
||||
|
||||
/**
|
||||
* 默认锁为全局锁
|
||||
* @since 0.0.1
|
||||
*/
|
||||
public static final String DEFAULT_KEY = "GLOBAL";
|
||||
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package com.github.houbb.lock.redis.constant;
|
||||
|
||||
/**
|
||||
* redis 锁常量
|
||||
*
|
||||
* @author binbin.hou
|
||||
* @since 0.0.1
|
||||
*/
|
||||
public final class LockRedisConst {
|
||||
|
||||
private LockRedisConst() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 加锁成功
|
||||
* @since 0.0.1
|
||||
*/
|
||||
public static final String LOCK_SUCCESS = "OK";
|
||||
|
||||
/**
|
||||
* 如果不存在则设置值
|
||||
* @since 0.0.1
|
||||
*/
|
||||
public static final String SET_IF_NOT_EXIST = "NX";
|
||||
|
||||
/**
|
||||
* 设置过期时间
|
||||
*
|
||||
* 单位:milliseconds
|
||||
* @since 0.0.1
|
||||
*/
|
||||
public static final String SET_WITH_EXPIRE_TIME = "PX";
|
||||
|
||||
/**
|
||||
* 解锁成功
|
||||
*
|
||||
* @since 0.0.1
|
||||
*/
|
||||
public static final Long RELEASE_SUCCESS = 1L;
|
||||
|
||||
|
||||
/**
|
||||
* 默认的失效时间
|
||||
*
|
||||
* 暂时定为 30min
|
||||
* @since 0.0.1
|
||||
*/
|
||||
public static final int DEFAULT_EXPIRE_MILLS = 1000 * 60 * 30;
|
||||
|
||||
/**
|
||||
* 默认锁为全局锁
|
||||
* @since 0.0.1
|
||||
*/
|
||||
public static final String DEFAULT_KEY = "GLOBAL";
|
||||
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.github.houbb.lock.redis.core;
|
||||
|
||||
import com.github.houbb.lock.api.core.ILock;
|
||||
import com.github.houbb.lock.redis.constant.LockRedisConst;
|
||||
import com.github.houbb.lock.redis.constant.LockConst;
|
||||
import com.github.houbb.wait.api.IWait;
|
||||
import com.github.houbb.wait.core.Waits;
|
||||
|
||||
@@ -41,12 +41,12 @@ public abstract class AbstractLock implements ILock {
|
||||
|
||||
@Override
|
||||
public boolean tryLock() {
|
||||
return tryLock(LockRedisConst.DEFAULT_KEY);
|
||||
return tryLock(LockConst.DEFAULT_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlock() {
|
||||
unlock(LockRedisConst.DEFAULT_KEY);
|
||||
unlock(LockConst.DEFAULT_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -81,7 +81,7 @@ public abstract class AbstractLock implements ILock {
|
||||
|
||||
@Override
|
||||
public synchronized boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
|
||||
return tryLock(time, unit, LockRedisConst.DEFAULT_KEY);
|
||||
return tryLock(time, unit, LockConst.DEFAULT_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.github.houbb.lock.redis.core;
|
||||
|
||||
import com.github.houbb.heaven.annotation.ThreadSafe;
|
||||
|
||||
/**
|
||||
* 无任何锁的操作
|
||||
*
|
||||
* @author binbin.hou
|
||||
* @since 0.0.3
|
||||
*/
|
||||
@ThreadSafe
|
||||
public class LockNone extends AbstractLock {
|
||||
|
||||
@Override
|
||||
public boolean tryLock(String key) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlock(String key) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -17,12 +17,12 @@ public class LockReadWrite implements IReadWriteLock {
|
||||
/**
|
||||
* 读次数统计
|
||||
*/
|
||||
private int readCount = 0;
|
||||
private volatile int readCount = 0;
|
||||
|
||||
/**
|
||||
* 写次数统计
|
||||
*/
|
||||
private int writeCount = 0;
|
||||
private volatile int writeCount = 0;
|
||||
|
||||
/**
|
||||
* 获取读锁,读锁在写锁不存在的时候才能获取
|
||||
|
||||
@@ -36,7 +36,7 @@ public class LockReadWriteOwner implements IReadWriteLock {
|
||||
/**
|
||||
* 写次数统计
|
||||
*/
|
||||
private int writeCount = 0;
|
||||
private volatile int writeCount = 0;
|
||||
|
||||
/**
|
||||
* 获取读锁,读锁在写锁不存在的时候才能获取
|
||||
|
||||
@@ -36,7 +36,7 @@ public class LockReadWriteRe implements IReadWriteLock {
|
||||
/**
|
||||
* 写次数统计
|
||||
*/
|
||||
private int writeCount = 0;
|
||||
private volatile int writeCount = 0;
|
||||
|
||||
/**
|
||||
* 获取读锁,读锁在写锁不存在的时候才能获取
|
||||
@@ -60,7 +60,7 @@ public class LockReadWriteRe implements IReadWriteLock {
|
||||
* 尝试获取读锁
|
||||
*
|
||||
* 读锁之间是不互斥的,这里后续需要优化。
|
||||
*
|
||||
*
|
||||
* @return 是否成功
|
||||
* @since 0.0.2
|
||||
*/
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
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 AbstractLock {
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryLock(String key) {
|
||||
final String requestId = id.id();
|
||||
IdThreadLocalHelper.put(requestId);
|
||||
|
||||
return redisOperator.lock(key, requestId, LockRedisConst.DEFAULT_EXPIRE_MILLS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public 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!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package com.github.houbb.lock.redis.core;
|
||||
|
||||
import com.github.houbb.lock.api.core.ILock;
|
||||
import com.github.houbb.lock.api.core.IReadWriteLock;
|
||||
|
||||
/**
|
||||
* 锁工具
|
||||
*
|
||||
* @author binbin.hou
|
||||
* @since 0.0.3
|
||||
*/
|
||||
public final class Locks {
|
||||
|
||||
private Locks(){}
|
||||
|
||||
/**
|
||||
* 无锁
|
||||
* @return 锁
|
||||
* @since 0.0.3
|
||||
*/
|
||||
public static ILock none() {
|
||||
return new LockNone();
|
||||
}
|
||||
|
||||
/**
|
||||
* 读写锁
|
||||
* @return 锁
|
||||
* @since 0.0.3
|
||||
*/
|
||||
public static IReadWriteLock readWrite() {
|
||||
return new LockReadWrite();
|
||||
}
|
||||
|
||||
/**
|
||||
* 读写锁
|
||||
* @return 锁
|
||||
* @since 0.0.3
|
||||
*/
|
||||
public static IReadWriteLock readWriteOwner() {
|
||||
return new LockReadWriteOwner();
|
||||
}
|
||||
|
||||
/**
|
||||
* 可重入读写锁
|
||||
* @return 锁
|
||||
* @since 0.0.3
|
||||
*/
|
||||
public static IReadWriteLock readWriteRe() {
|
||||
return new LockReadWriteRe();
|
||||
}
|
||||
|
||||
/**
|
||||
* 自旋锁
|
||||
* @return 锁
|
||||
* @since 0.0.3
|
||||
*/
|
||||
public static ILock spin() {
|
||||
return new LockSpin();
|
||||
}
|
||||
|
||||
/**
|
||||
* 可重入自旋锁
|
||||
* @return 锁
|
||||
* @since 0.0.3
|
||||
*/
|
||||
public static ILock spinRe() {
|
||||
return new LockSpinRe();
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待通知锁
|
||||
* @return 锁
|
||||
* @since 0.0.3
|
||||
*/
|
||||
public static ILock waitNotify() {
|
||||
return new LockWaitNotify();
|
||||
}
|
||||
|
||||
/**
|
||||
* 可重入等待通知锁
|
||||
* @return 锁
|
||||
* @since 0.0.3
|
||||
*/
|
||||
public static ILock waitNotifyRe() {
|
||||
return new LockWaitNotifyRe();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package com.github.houbb.lock.redis.exception;
|
||||
|
||||
/**
|
||||
* @author binbin.hou
|
||||
* @since 0.0.1
|
||||
*/
|
||||
public class LockRedisException extends RuntimeException {
|
||||
|
||||
public LockRedisException() {
|
||||
}
|
||||
|
||||
public LockRedisException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public LockRedisException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public LockRedisException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public LockRedisException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
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);
|
||||
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
package com.github.houbb.lock.redis.support.operator.impl;
|
||||
|
||||
import com.github.houbb.lock.redis.constant.LockRedisConst;
|
||||
import com.github.houbb.lock.redis.support.operator.IOperator;
|
||||
import redis.clients.jedis.Jedis;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* Redis 客户端
|
||||
* @author binbin.hou
|
||||
* @since 0.0.1
|
||||
*/
|
||||
public class JedisOperator implements IOperator {
|
||||
|
||||
/**
|
||||
* jedis 客户端
|
||||
* @since 0.0.1
|
||||
*/
|
||||
private final Jedis jedis;
|
||||
|
||||
public JedisOperator(Jedis jedis) {
|
||||
this.jedis = jedis;
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试获取分布式锁
|
||||
*
|
||||
* expireTimeMills 保证当前进程挂掉,也能释放锁
|
||||
*
|
||||
* requestId 保证解锁的是当前进程(锁的持有者)
|
||||
*
|
||||
* @param lockKey 锁
|
||||
* @param requestId 请求标识
|
||||
* @param expireTimeMills 超期时间
|
||||
* @return 是否获取成功
|
||||
* @since 0.0.1
|
||||
*/
|
||||
@Override
|
||||
public boolean lock(String lockKey, String requestId, int expireTimeMills) {
|
||||
String result = jedis.set(lockKey, requestId, LockRedisConst.SET_IF_NOT_EXIST, LockRedisConst.SET_WITH_EXPIRE_TIME, expireTimeMills);
|
||||
return LockRedisConst.LOCK_SUCCESS.equals(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解锁
|
||||
*
|
||||
* (1)使用 requestId,保证为当前锁的持有者
|
||||
* (2)使用 lua 脚本,保证执行的原子性。
|
||||
*
|
||||
* @param lockKey 锁 key
|
||||
* @param requestId 请求标识
|
||||
* @return 结果
|
||||
* @since 0.0.1
|
||||
*/
|
||||
@Override
|
||||
public boolean unlock(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));
|
||||
return LockRedisConst.RELEASE_SUCCESS.equals(result);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
package com.github.houbb.lock.redis.support;
|
||||
Reference in New Issue
Block a user