release branch 0.0.4
This commit is contained in:
@@ -36,7 +36,15 @@
|
||||
<groupId>com.github.houbb</groupId>
|
||||
<artifactId>log-integration</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.houbb</groupId>
|
||||
<artifactId>common-cache-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.houbb</groupId>
|
||||
<artifactId>redis-config-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
package com.github.houbb.lock.core.bs;
|
||||
|
||||
import com.github.houbb.common.cache.api.service.ICommonCacheService;
|
||||
import com.github.houbb.heaven.util.common.ArgUtil;
|
||||
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.api.support.IOperator;
|
||||
import com.github.houbb.lock.core.support.simple.SimpleLock;
|
||||
import com.github.houbb.wait.api.IWait;
|
||||
import com.github.houbb.wait.core.Waits;
|
||||
import com.github.houbb.lock.api.core.ILockSupport;
|
||||
import com.github.houbb.lock.api.core.ILockSupportContext;
|
||||
import com.github.houbb.lock.core.constant.LockConst;
|
||||
import com.github.houbb.lock.core.support.lock.LockSupportContext;
|
||||
import com.github.houbb.lock.core.support.lock.RedisLockSupport;
|
||||
import com.github.houbb.redis.config.core.factory.JedisRedisServiceFactory;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 锁引导类
|
||||
@@ -15,69 +20,46 @@ import com.github.houbb.wait.core.Waits;
|
||||
* @author binbin.hou
|
||||
* @since 0.0.4
|
||||
*/
|
||||
public final class LockBs {
|
||||
public final class LockBs implements ILock{
|
||||
|
||||
private LockBs(){}
|
||||
|
||||
/**
|
||||
* 清空初始化延迟时间
|
||||
* @since 0.0.4
|
||||
*/
|
||||
private long clearInitDelaySeconds = 60;
|
||||
public static LockBs newInstance() {
|
||||
return new LockBs();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空初始化周期
|
||||
* 加锁锁定时间
|
||||
* @since 0.0.4
|
||||
*/
|
||||
private long clearPeriodSeconds = 60;
|
||||
|
||||
/**
|
||||
* 是否启用清空任务
|
||||
* @since 0.0.4
|
||||
*/
|
||||
private boolean enableClearTask = true;
|
||||
|
||||
/**
|
||||
* 锁等待
|
||||
* @since 0.0.1
|
||||
*/
|
||||
protected IWait waits = Waits.threadSleep();
|
||||
private int lockExpireMills = LockConst.DEFAULT_EXPIRE_MILLS;
|
||||
|
||||
/**
|
||||
* 标识策略
|
||||
* @since 0.0.4
|
||||
*/
|
||||
protected Id id = Ids.uuid32();
|
||||
private Id id = Ids.uuid32();
|
||||
|
||||
/**
|
||||
* 操作策略
|
||||
* 缓存策略
|
||||
* @since 0.0.4
|
||||
*/
|
||||
protected IOperator operator;
|
||||
private ICommonCacheService commonCacheService = JedisRedisServiceFactory.simple("127.0.0.1", 6379);
|
||||
|
||||
public static LockBs newInstance(final IOperator operator) {
|
||||
return new LockBs().operator(operator);
|
||||
}
|
||||
/**
|
||||
* 锁支持策略
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private ILockSupport lockSupport = new RedisLockSupport();
|
||||
|
||||
public LockBs clearInitDelaySeconds(long clearInitDelaySeconds) {
|
||||
this.clearInitDelaySeconds = clearInitDelaySeconds;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 锁上下文
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private ILockSupportContext lockSupportContext = null;
|
||||
|
||||
public LockBs clearPeriodSeconds(long clearPeriodSeconds) {
|
||||
this.clearPeriodSeconds = clearPeriodSeconds;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LockBs enableClearTask(boolean enableClearTask) {
|
||||
this.enableClearTask = enableClearTask;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LockBs waits(IWait waits) {
|
||||
ArgUtil.notNull(waits, "waits");
|
||||
|
||||
this.waits = waits;
|
||||
public LockBs lockExpireMills(int lockExpireMills) {
|
||||
this.lockExpireMills = lockExpireMills;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -88,24 +70,62 @@ public final class LockBs {
|
||||
return this;
|
||||
}
|
||||
|
||||
public LockBs operator(IOperator operator) {
|
||||
ArgUtil.notNull(operator, "operator");
|
||||
public LockBs commonCacheService(ICommonCacheService commonCacheService) {
|
||||
ArgUtil.notNull(commonCacheService, "commonCacheService");
|
||||
|
||||
this.operator = operator;
|
||||
this.commonCacheService = commonCacheService;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ILock lock() {
|
||||
ArgUtil.notNull(operator, "operator");
|
||||
public LockBs lockSupport(ILockSupport lockSupport) {
|
||||
ArgUtil.notNull(lockSupport, "lockSupport");
|
||||
|
||||
return SimpleLock.newInstance()
|
||||
.waits(waits)
|
||||
.id(id)
|
||||
.operator(operator)
|
||||
.enableClearTask(enableClearTask)
|
||||
.clearInitDelaySeconds(clearInitDelaySeconds)
|
||||
.clearPeriodSeconds(clearPeriodSeconds)
|
||||
.init();
|
||||
this.lockSupport = lockSupport;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
public LockBs init() {
|
||||
this.lockSupportContext = LockSupportContext.newInstance()
|
||||
.id(id)
|
||||
.commonCacheService(commonCacheService)
|
||||
.lockExpireMills(lockExpireMills);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryLock(long time, TimeUnit unit, String key) {
|
||||
ArgUtil.notEmpty(key, "key");
|
||||
this.checkInitStatus();
|
||||
|
||||
|
||||
return this.lockSupport.tryLock(time, unit, key, lockSupportContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryLock(String key) {
|
||||
ArgUtil.notEmpty(key, "key");
|
||||
this.checkInitStatus();
|
||||
|
||||
return this.lockSupport.tryLock(key, lockSupportContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unlock(String key) {
|
||||
ArgUtil.notEmpty(key, "key");
|
||||
this.checkInitStatus();
|
||||
|
||||
return this.lockSupport.unlock(key, lockSupportContext);
|
||||
}
|
||||
|
||||
|
||||
private void checkInitStatus() {
|
||||
ArgUtil.notNull(lockSupportContext, "please init() first!");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,184 +0,0 @@
|
||||
package com.github.houbb.lock.core.core;
|
||||
|
||||
import com.github.houbb.heaven.util.common.ArgUtil;
|
||||
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.api.support.IOperator;
|
||||
import com.github.houbb.lock.core.constant.LockConst;
|
||||
import com.github.houbb.wait.api.IWait;
|
||||
import com.github.houbb.wait.core.Waits;
|
||||
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
|
||||
/**
|
||||
* 抽象实现
|
||||
* @author binbin.hou
|
||||
* @since 0.0.1
|
||||
*/
|
||||
public abstract class AbstractLock implements ILock {
|
||||
|
||||
/**
|
||||
* 锁等待
|
||||
* @since 0.0.1
|
||||
*/
|
||||
protected IWait waits = Waits.threadSleep();
|
||||
|
||||
/**
|
||||
* 标识策略
|
||||
* @since 0.0.4
|
||||
*/
|
||||
protected Id id = Ids.uuid32();
|
||||
|
||||
/**
|
||||
* 操作策略
|
||||
* @since 0.0.4
|
||||
*/
|
||||
protected IOperator operator;
|
||||
|
||||
/**
|
||||
* 清空初始化延迟时间
|
||||
* @since 0.0.4
|
||||
*/
|
||||
private long clearInitDelaySeconds = 5;
|
||||
|
||||
/**
|
||||
* 清空初始化周期
|
||||
* @since 0.0.4
|
||||
*/
|
||||
private long clearPeriodSeconds = 5;
|
||||
|
||||
/**
|
||||
* 是否启用清空任务
|
||||
* @since 0.0.4
|
||||
*/
|
||||
private boolean enableClearTask = true;
|
||||
|
||||
public AbstractLock waits(IWait waits) {
|
||||
this.waits = waits;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AbstractLock id(Id id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AbstractLock operator(IOperator operator) {
|
||||
this.operator = operator;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AbstractLock clearInitDelaySeconds(long clearInitDelaySeconds) {
|
||||
this.clearInitDelaySeconds = clearInitDelaySeconds;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AbstractLock clearPeriodSeconds(long clearPeriodSeconds) {
|
||||
this.clearPeriodSeconds = clearPeriodSeconds;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AbstractLock enableClearTask(boolean enableClearTask) {
|
||||
this.enableClearTask = enableClearTask;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
* @since 0.0.4
|
||||
*/
|
||||
public AbstractLock init() {
|
||||
// 参数校验
|
||||
ArgUtil.notNull(operator, "operator");
|
||||
|
||||
// 初始化任务
|
||||
initClearExpireKey();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化清空任务
|
||||
* @since 0.0.6
|
||||
*/
|
||||
private void initClearExpireKey() {
|
||||
if(!enableClearTask) {
|
||||
return;
|
||||
}
|
||||
|
||||
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
|
||||
//5S 清理一次
|
||||
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
operator.clearExpireLock();
|
||||
}
|
||||
}, clearInitDelaySeconds, clearPeriodSeconds, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void lock() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lockInterruptibly() throws InterruptedException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryLock() {
|
||||
return tryLock(LockConst.DEFAULT_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlock() {
|
||||
unlock(LockConst.DEFAULT_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryLock(long time, TimeUnit unit, String key) throws InterruptedException {
|
||||
long startTimeMills = System.currentTimeMillis();
|
||||
|
||||
// 一次获取,直接成功
|
||||
boolean result = this.tryLock(key);
|
||||
if(result) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 时间判断
|
||||
if(time <= 0) {
|
||||
return false;
|
||||
}
|
||||
long durationMills = unit.toMillis(time);
|
||||
long endMills = startTimeMills + durationMills;
|
||||
|
||||
// 循环等待
|
||||
while (System.currentTimeMillis() < endMills) {
|
||||
result = tryLock(key);
|
||||
if(result) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 等待 1ms
|
||||
waits.wait(TimeUnit.MILLISECONDS, 1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
|
||||
return tryLock(time, unit, LockConst.DEFAULT_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Condition newCondition() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package com.github.houbb.lock.core.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) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
package com.github.houbb.lock.core.core;
|
||||
|
||||
import com.github.houbb.lock.api.core.IReadWriteLock;
|
||||
import com.github.houbb.log.integration.core.Log;
|
||||
import com.github.houbb.log.integration.core.LogFactory;
|
||||
|
||||
/**
|
||||
* 读写锁实现
|
||||
*
|
||||
* @author binbin.hou
|
||||
* @since 0.0.2
|
||||
*/
|
||||
public class LockReadWrite implements IReadWriteLock {
|
||||
|
||||
private static final Log log = LogFactory.getLog(LockReadWrite.class);
|
||||
|
||||
/**
|
||||
* 读次数统计
|
||||
*/
|
||||
private volatile int readCount = 0;
|
||||
|
||||
/**
|
||||
* 写次数统计
|
||||
*/
|
||||
private volatile int writeCount = 0;
|
||||
|
||||
/**
|
||||
* 获取读锁,读锁在写锁不存在的时候才能获取
|
||||
*
|
||||
* @since 0.0.2
|
||||
*/
|
||||
@Override
|
||||
public synchronized void lockRead() {
|
||||
try {
|
||||
// 写锁存在,需要wait
|
||||
while (!tryLockRead()) {
|
||||
wait();
|
||||
}
|
||||
|
||||
readCount++;
|
||||
} catch (InterruptedException e) {
|
||||
Thread.interrupted();
|
||||
// 忽略打断
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试获取读锁
|
||||
*
|
||||
* @return 是否成功
|
||||
* @since 0.0.2
|
||||
*/
|
||||
private boolean tryLockRead() {
|
||||
if (writeCount > 0) {
|
||||
log.debug("当前有写锁,获取读锁失败");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放读锁
|
||||
*
|
||||
* @since 0.0.2
|
||||
*/
|
||||
@Override
|
||||
public synchronized void unlockRead() {
|
||||
readCount--;
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取写锁
|
||||
*
|
||||
* @since 0.0.2
|
||||
*/
|
||||
@Override
|
||||
public synchronized void lockWrite() {
|
||||
try {
|
||||
// 写锁存在,需要wait
|
||||
while (!tryLockWrite()) {
|
||||
wait();
|
||||
}
|
||||
|
||||
// 此时已经不存在获取写锁的线程了,因此占坑,防止写锁饥饿
|
||||
writeCount++;
|
||||
} catch (InterruptedException e) {
|
||||
Thread.interrupted();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试获取写锁
|
||||
*
|
||||
* @return 是否成功
|
||||
* @since 0.0.2
|
||||
*/
|
||||
private boolean tryLockWrite() {
|
||||
if (writeCount > 0) {
|
||||
log.debug("当前有其他写锁,获取写锁失败");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 读锁
|
||||
if (readCount > 0) {
|
||||
log.debug("当前有其他读锁,获取写锁失败。");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放写锁
|
||||
*
|
||||
* @since 0.0.2
|
||||
*/
|
||||
@Override
|
||||
public synchronized void unlockWrite() {
|
||||
writeCount--;
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,160 +0,0 @@
|
||||
package com.github.houbb.lock.core.core;
|
||||
|
||||
import com.github.houbb.lock.api.core.IReadWriteLock;
|
||||
import com.github.houbb.log.integration.core.Log;
|
||||
import com.github.houbb.log.integration.core.LogFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* 读写锁实现-保证释放锁时为锁的持有者
|
||||
*
|
||||
* @author binbin.hou
|
||||
* @since 0.0.2
|
||||
*/
|
||||
public class LockReadWriteOwner implements IReadWriteLock {
|
||||
|
||||
private static final Log log = LogFactory.getLog(LockReadWriteOwner.class);
|
||||
|
||||
/**
|
||||
* 如果使用类似 write 的方式,会导致读锁只能有一个。
|
||||
* 调整为使用 HashMap 存放读的信息
|
||||
*
|
||||
* @since 0.0.2
|
||||
*/
|
||||
private final Map<Thread, Integer> readCountMap = new HashMap<>();
|
||||
|
||||
/**
|
||||
* volatile 引用,保证线程间的可见性+易变性
|
||||
*
|
||||
* @since 0.0.2
|
||||
*/
|
||||
private final AtomicReference<Thread> writeOwner = new AtomicReference<>();
|
||||
|
||||
/**
|
||||
* 写次数统计
|
||||
*/
|
||||
private volatile int writeCount = 0;
|
||||
|
||||
/**
|
||||
* 获取读锁,读锁在写锁不存在的时候才能获取
|
||||
*
|
||||
* @since 0.0.2
|
||||
*/
|
||||
@Override
|
||||
public synchronized void lockRead() {
|
||||
try {
|
||||
// 写锁存在,需要wait
|
||||
while (!tryLockRead()) {
|
||||
log.debug("获取读锁失败,进入等待状态。");
|
||||
wait();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
Thread.interrupted();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试获取读锁
|
||||
*
|
||||
* 读锁之间是不互斥的,这里后续需要优化。
|
||||
*
|
||||
* @return 是否成功
|
||||
* @since 0.0.2
|
||||
*/
|
||||
private boolean tryLockRead() {
|
||||
if (writeCount > 0) {
|
||||
log.debug("当前有写锁,获取读锁失败");
|
||||
return false;
|
||||
}
|
||||
|
||||
Thread currentThread = Thread.currentThread();
|
||||
// 次数暂时固定为1,后面如果实现可重入,这里可以改进。
|
||||
this.readCountMap.put(currentThread, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放读锁
|
||||
*
|
||||
* @since 0.0.2
|
||||
*/
|
||||
@Override
|
||||
public synchronized void unlockRead() {
|
||||
Thread currentThread = Thread.currentThread();
|
||||
Integer readCount = readCountMap.get(currentThread);
|
||||
|
||||
if (readCount == null) {
|
||||
throw new RuntimeException("当前线程未持有任何读锁,释放锁失败!");
|
||||
} else {
|
||||
log.debug("释放读锁,唤醒所有等待线程。");
|
||||
readCountMap.remove(currentThread);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取写锁
|
||||
*
|
||||
* @since 0.0.2
|
||||
*/
|
||||
@Override
|
||||
public synchronized void lockWrite() {
|
||||
try {
|
||||
// 写锁存在,需要wait
|
||||
while (!tryLockWrite()) {
|
||||
wait();
|
||||
}
|
||||
|
||||
// 此时已经不存在获取写锁的线程了,因此占坑,防止写锁饥饿
|
||||
writeCount++;
|
||||
} catch (InterruptedException e) {
|
||||
Thread.interrupted();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试获取写锁
|
||||
*
|
||||
* @return 是否成功
|
||||
* @since 0.0.2
|
||||
*/
|
||||
private boolean tryLockWrite() {
|
||||
if (writeCount > 0) {
|
||||
log.debug("当前有其他写锁,获取写锁失败");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 读锁
|
||||
if (!readCountMap.isEmpty()) {
|
||||
log.debug("当前有其他读锁,获取写锁失败。");
|
||||
return false;
|
||||
}
|
||||
|
||||
Thread currentThread = Thread.currentThread();
|
||||
boolean result = writeOwner.compareAndSet(null, currentThread);
|
||||
log.debug("尝试获取写锁结果:{}", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放写锁
|
||||
*
|
||||
* @since 0.0.2
|
||||
*/
|
||||
@Override
|
||||
public synchronized void unlockWrite() {
|
||||
boolean toNullResult = writeOwner.compareAndSet(Thread.currentThread(), null);
|
||||
|
||||
if (toNullResult) {
|
||||
writeCount--;
|
||||
log.debug("写锁释放,唤醒所有等待线程。");
|
||||
notifyAll();
|
||||
} else {
|
||||
throw new RuntimeException("释放写锁失败");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,195 +0,0 @@
|
||||
package com.github.houbb.lock.core.core;
|
||||
|
||||
import com.github.houbb.lock.api.core.IReadWriteLock;
|
||||
import com.github.houbb.log.integration.core.Log;
|
||||
import com.github.houbb.log.integration.core.LogFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* 读写锁实现-可重入锁
|
||||
*
|
||||
* @author binbin.hou
|
||||
* @since 0.0.2
|
||||
*/
|
||||
public class LockReadWriteRe implements IReadWriteLock {
|
||||
|
||||
private static final Log log = LogFactory.getLog(LockReadWriteRe.class);
|
||||
|
||||
/**
|
||||
* 如果使用类似 write 的方式,会导致读锁只能有一个。
|
||||
* 调整为使用 HashMap 存放读的信息
|
||||
*
|
||||
* @since 0.0.2
|
||||
*/
|
||||
private final Map<Thread, Integer> readCountMap = new HashMap<>();
|
||||
|
||||
/**
|
||||
* volatile 引用,保证线程间的可见性+易变性
|
||||
*
|
||||
* @since 0.0.2
|
||||
*/
|
||||
private final AtomicReference<Thread> writeOwner = new AtomicReference<>();
|
||||
|
||||
/**
|
||||
* 写次数统计
|
||||
*/
|
||||
private volatile int writeCount = 0;
|
||||
|
||||
/**
|
||||
* 获取读锁,读锁在写锁不存在的时候才能获取
|
||||
*
|
||||
* @since 0.0.2
|
||||
*/
|
||||
@Override
|
||||
public synchronized void lockRead() {
|
||||
try {
|
||||
// 写锁存在,需要wait
|
||||
while (!tryLockRead()) {
|
||||
log.debug("获取读锁失败,进入等待状态。");
|
||||
wait();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
Thread.interrupted();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试获取读锁
|
||||
*
|
||||
* 读锁之间是不互斥的,这里后续需要优化。
|
||||
*
|
||||
* @return 是否成功
|
||||
* @since 0.0.2
|
||||
*/
|
||||
private boolean tryLockRead() {
|
||||
if (writeCount > 0) {
|
||||
log.debug("当前有写锁,获取读锁失败");
|
||||
return false;
|
||||
}
|
||||
|
||||
Thread currentThread = Thread.currentThread();
|
||||
Integer count = readCountMap.get(currentThread);
|
||||
if(count == null) {
|
||||
count = 0;
|
||||
}
|
||||
count++;
|
||||
|
||||
this.readCountMap.put(currentThread, count);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放读锁
|
||||
*
|
||||
* @since 0.0.2
|
||||
*/
|
||||
@Override
|
||||
public synchronized void unlockRead() {
|
||||
Thread currentThread = Thread.currentThread();
|
||||
Integer readCount = readCountMap.get(currentThread);
|
||||
|
||||
if (readCount == null) {
|
||||
throw new RuntimeException("当前线程未持有任何读锁,释放锁失败!");
|
||||
} else {
|
||||
readCount--;
|
||||
|
||||
// 已经是最后一次
|
||||
if(readCount == 0) {
|
||||
readCountMap.remove(currentThread);
|
||||
} else {
|
||||
readCountMap.put(currentThread, readCount);
|
||||
}
|
||||
|
||||
log.debug("释放读锁,唤醒所有等待线程。");
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取写锁
|
||||
*
|
||||
* @since 0.0.2
|
||||
*/
|
||||
@Override
|
||||
public synchronized void lockWrite() {
|
||||
try {
|
||||
// 写锁存在,需要wait
|
||||
while (!tryLockWrite()) {
|
||||
log.debug("获取写锁失败,进入等待状态。");
|
||||
wait();
|
||||
}
|
||||
|
||||
// 此时已经不存在获取写锁的线程了,因此占坑,防止写锁饥饿
|
||||
writeCount++;
|
||||
} catch (InterruptedException e) {
|
||||
Thread.interrupted();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试获取写锁
|
||||
*
|
||||
* @return 是否成功
|
||||
* @since 0.0.2
|
||||
*/
|
||||
private boolean tryLockWrite() {
|
||||
if (writeCount > 0) {
|
||||
log.debug("当前有其他写锁,获取写锁失败");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 读锁
|
||||
if (!readCountMap.isEmpty()) {
|
||||
log.debug("当前有其他读锁,获取写锁失败。");
|
||||
return false;
|
||||
}
|
||||
|
||||
Thread currentThread = Thread.currentThread();
|
||||
// 多次重入
|
||||
if(writeOwner.get() == currentThread) {
|
||||
log.debug("为当前写线程多次重入,直接返回 true。");
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean result = writeOwner.compareAndSet(null, currentThread);
|
||||
log.debug("尝试获取写锁结果:{}", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放写锁
|
||||
*
|
||||
* @since 0.0.2
|
||||
*/
|
||||
@Override
|
||||
public synchronized void unlockWrite() {
|
||||
Thread currentThread = Thread.currentThread();
|
||||
// 多次重入释放(当次数多于1时直接返回,否则需要释放 owner 信息)
|
||||
if(writeCount > 1 && (currentThread == writeOwner.get())) {
|
||||
log.debug("当前为写锁释放多次重入,直接返回成功。");
|
||||
|
||||
unlockWriteNotify();
|
||||
return;
|
||||
}
|
||||
|
||||
boolean toNullResult = writeOwner.compareAndSet(currentThread, null);
|
||||
if (toNullResult) {
|
||||
unlockWriteNotify();
|
||||
} else {
|
||||
throw new RuntimeException("释放写锁失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放写锁并且通知
|
||||
*/
|
||||
private synchronized void unlockWriteNotify() {
|
||||
writeCount--;
|
||||
log.debug("释放写锁成功,唤醒所有等待线程。");
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package com.github.houbb.lock.core.core;
|
||||
|
||||
import com.github.houbb.lock.core.exception.LockRuntimeException;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* 自旋锁
|
||||
* @author binbin.hou
|
||||
* @since 0.0.2
|
||||
*/
|
||||
public class LockSpin extends AbstractLock {
|
||||
|
||||
/**
|
||||
* volatile 引用,保证线程间的可见性+易变性
|
||||
*
|
||||
* @since 0.0.2
|
||||
*/
|
||||
private AtomicReference<Thread> owner =new AtomicReference<>();
|
||||
|
||||
@Override
|
||||
public void lock() {
|
||||
// 循环等待,直到获取到锁
|
||||
while (!tryLock()) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryLock(String key) {
|
||||
Thread current = Thread.currentThread();
|
||||
// CAS
|
||||
return owner.compareAndSet(null, current);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlock(String key) {
|
||||
Thread current = Thread.currentThread();
|
||||
boolean result = owner.compareAndSet(current, null);
|
||||
if(!result) {
|
||||
throw new LockRuntimeException("解锁失败");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
package com.github.houbb.lock.core.core;
|
||||
|
||||
import com.github.houbb.heaven.util.util.DateUtil;
|
||||
import com.github.houbb.lock.core.exception.LockRuntimeException;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* 自旋锁-可重入
|
||||
* @author binbin.hou
|
||||
* @since 0.0.2
|
||||
*/
|
||||
public class LockSpinRe extends AbstractLock {
|
||||
|
||||
/**
|
||||
* volatile 引用,保证线程间的可见性+易变性
|
||||
*
|
||||
* @since 0.0.2
|
||||
*/
|
||||
private AtomicReference<Thread> owner =new AtomicReference<>();
|
||||
|
||||
/**
|
||||
* 计数统计类
|
||||
*
|
||||
* @since 0.0.2
|
||||
*/
|
||||
private AtomicLong count = new AtomicLong(0);
|
||||
|
||||
@Override
|
||||
public void lock() {
|
||||
// 循环等待,直到获取到锁
|
||||
while (!tryLock()) {
|
||||
// sleep
|
||||
DateUtil.sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryLock(String key) {
|
||||
Thread current = Thread.currentThread();
|
||||
// 判断是否已经拥有此锁
|
||||
if(current == owner.get()) {
|
||||
// 原子性自增 1
|
||||
count.incrementAndGet();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// CAS
|
||||
return owner.compareAndSet(null, current);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlock(String key) {
|
||||
Thread current = Thread.currentThread();
|
||||
|
||||
// 可重入实现
|
||||
if(owner.get() == current && count.get() != 0) {
|
||||
count.decrementAndGet();
|
||||
return;
|
||||
}
|
||||
|
||||
boolean result = owner.compareAndSet(current, null);
|
||||
if(!result) {
|
||||
throw new LockRuntimeException("解锁失败");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
package com.github.houbb.lock.core.core;
|
||||
|
||||
import com.github.houbb.lock.core.exception.LockRuntimeException;
|
||||
import com.github.houbb.log.integration.core.Log;
|
||||
import com.github.houbb.log.integration.core.LogFactory;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* 等待通知的锁实现
|
||||
* @author binbin.hou
|
||||
* @since 0.0.2
|
||||
*/
|
||||
public class LockWaitNotify extends AbstractLock {
|
||||
|
||||
private static final Log log = LogFactory.getLog(LockWaitNotify.class);
|
||||
|
||||
/**
|
||||
* volatile 引用,保证线程间的可见性+易变性
|
||||
*
|
||||
* @since 0.0.2
|
||||
*/
|
||||
private AtomicReference<Thread> owner =new AtomicReference<>();
|
||||
|
||||
@Override
|
||||
public synchronized void lock() {
|
||||
while (!tryLock()) {
|
||||
try {
|
||||
log.debug("等待被唤醒");
|
||||
wait();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
// 是否可以被打断
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryLock(String key) {
|
||||
Thread current = Thread.currentThread();
|
||||
// CAS
|
||||
boolean result = owner.compareAndSet(null, current);
|
||||
log.debug("尝试获取锁结果:{}", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void unlock(String key) {
|
||||
Thread current = Thread.currentThread();
|
||||
boolean result = owner.compareAndSet(current, null);
|
||||
if(!result) {
|
||||
throw new LockRuntimeException("解锁失败");
|
||||
}
|
||||
|
||||
// 唤醒等待中的线程
|
||||
log.debug("唤醒等待的进程");
|
||||
notify();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
package com.github.houbb.lock.core.core;
|
||||
|
||||
import com.github.houbb.lock.core.exception.LockRuntimeException;
|
||||
import com.github.houbb.log.integration.core.Log;
|
||||
import com.github.houbb.log.integration.core.LogFactory;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* 等待通知的锁实现-可重入
|
||||
* @author binbin.hou
|
||||
* @since 0.0.2
|
||||
*/
|
||||
public class LockWaitNotifyRe extends AbstractLock {
|
||||
|
||||
private static final Log log = LogFactory.getLog(LockWaitNotifyRe.class);
|
||||
|
||||
/**
|
||||
* volatile 引用,保证线程间的可见性+易变性
|
||||
*
|
||||
* @since 0.0.2
|
||||
*/
|
||||
private AtomicReference<Thread> owner =new AtomicReference<>();
|
||||
|
||||
/**
|
||||
* 次数统计
|
||||
* @since 0.0.2
|
||||
*/
|
||||
private AtomicInteger count = new AtomicInteger(0);
|
||||
|
||||
@Override
|
||||
public synchronized void lock() {
|
||||
while (!tryLock()) {
|
||||
try {
|
||||
log.debug("等待被唤醒");
|
||||
wait();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
// 是否可以被打断
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryLock(String key) {
|
||||
Thread current = Thread.currentThread();
|
||||
|
||||
//可重入实现
|
||||
if(current == owner.get()) {
|
||||
count.incrementAndGet();
|
||||
log.debug("当前线程已经拥有锁,直接返回 true");
|
||||
return true;
|
||||
}
|
||||
|
||||
// CAS
|
||||
boolean result = owner.compareAndSet(null, current);
|
||||
log.debug("尝试获取锁结果:{}", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void unlock(String key) {
|
||||
Thread current = Thread.currentThread();
|
||||
|
||||
// 可重入实现
|
||||
if(owner.get() == current && count.get() != 0) {
|
||||
count.decrementAndGet();
|
||||
notifyAndLog();
|
||||
return;
|
||||
}
|
||||
|
||||
boolean result = owner.compareAndSet(current, null);
|
||||
if(!result) {
|
||||
throw new LockRuntimeException("解锁失败");
|
||||
}
|
||||
|
||||
notifyAndLog();
|
||||
}
|
||||
|
||||
private void notifyAndLog() {
|
||||
// 唤醒等待中的线程
|
||||
log.debug("唤醒等待的进程");
|
||||
notify();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
package com.github.houbb.lock.core.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.core.exception;
|
||||
|
||||
/**
|
||||
* @author binbin.hou
|
||||
* @since 0.0.2
|
||||
*/
|
||||
public class LockRuntimeException extends RuntimeException {
|
||||
|
||||
public LockRuntimeException() {
|
||||
}
|
||||
|
||||
public LockRuntimeException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public LockRuntimeException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public LockRuntimeException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public LockRuntimeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.github.houbb.lock.core.support.lock;
|
||||
|
||||
import com.github.houbb.common.cache.api.service.ICommonCacheService;
|
||||
import com.github.houbb.id.api.Id;
|
||||
import com.github.houbb.lock.api.core.ILockSupportContext;
|
||||
|
||||
/**
|
||||
* 分布式锁接口定义
|
||||
* @author binbin.hou
|
||||
* @since 0.0.1
|
||||
*/
|
||||
public class LockSupportContext implements ILockSupportContext {
|
||||
|
||||
public static LockSupportContext newInstance() {
|
||||
return new LockSupportContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* 标识策略
|
||||
* @since 0.0.4
|
||||
*/
|
||||
private Id id;
|
||||
|
||||
/**
|
||||
* 缓存策略
|
||||
* @since 0.0.4
|
||||
*/
|
||||
private ICommonCacheService commonCacheService;
|
||||
|
||||
/**
|
||||
* 锁的过期时间
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private int lockExpireMills;
|
||||
|
||||
@Override
|
||||
public Id id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public LockSupportContext id(Id id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICommonCacheService commonCacheService() {
|
||||
return commonCacheService;
|
||||
}
|
||||
|
||||
public LockSupportContext commonCacheService(ICommonCacheService commonCacheService) {
|
||||
this.commonCacheService = commonCacheService;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lockExpireMills() {
|
||||
return lockExpireMills;
|
||||
}
|
||||
|
||||
public LockSupportContext lockExpireMills(int lockExpireMills) {
|
||||
this.lockExpireMills = lockExpireMills;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package com.github.houbb.lock.core.support.lock;
|
||||
|
||||
import com.github.houbb.common.cache.api.service.ICommonCacheService;
|
||||
import com.github.houbb.id.api.Id;
|
||||
import com.github.houbb.id.core.util.IdThreadLocalHelper;
|
||||
import com.github.houbb.lock.api.core.ILockSupport;
|
||||
import com.github.houbb.lock.api.core.ILockSupportContext;
|
||||
import com.github.houbb.log.integration.core.Log;
|
||||
import com.github.houbb.log.integration.core.LogFactory;
|
||||
import com.github.houbb.redis.config.core.constant.JedisConst;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 分布式锁接口定义
|
||||
* @author binbin.hou
|
||||
* @since 0.0.1
|
||||
*/
|
||||
public class RedisLockSupport implements ILockSupport {
|
||||
|
||||
private final Log log = LogFactory.getLog(RedisLockSupport.class);
|
||||
|
||||
@Override
|
||||
public boolean tryLock(long time, TimeUnit unit, String key, ILockSupportContext context) {
|
||||
long startTimeMills = System.currentTimeMillis();
|
||||
|
||||
// 一次获取,直接成功
|
||||
boolean result = this.tryLock(key, context);
|
||||
if(result) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 时间判断
|
||||
if(time <= 0) {
|
||||
return false;
|
||||
}
|
||||
long durationMills = unit.toMillis(time);
|
||||
long endMills = startTimeMills + durationMills;
|
||||
|
||||
// 循环等待
|
||||
while (System.currentTimeMillis() < endMills) {
|
||||
result = tryLock(key, context);
|
||||
if(result) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 等待 1ms
|
||||
try {
|
||||
TimeUnit.MILLISECONDS.sleep(1);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryLock(String key, ILockSupportContext context) {
|
||||
log.info("开始尝试获取锁 {}", key);
|
||||
|
||||
// 生成当前线程的唯一标识
|
||||
Id id = context.id();
|
||||
final String requestId = id.id();
|
||||
IdThreadLocalHelper.put(requestId);
|
||||
log.info("开始尝试获取锁 requestId: {}", requestId);
|
||||
|
||||
final ICommonCacheService commonCacheService = context.commonCacheService();
|
||||
|
||||
final int lockExpireMills = context.lockExpireMills();
|
||||
|
||||
String result = commonCacheService.set(key, requestId, JedisConst.SET_IF_NOT_EXIST, JedisConst.SET_WITH_EXPIRE_TIME, lockExpireMills);
|
||||
return JedisConst.OK.equalsIgnoreCase(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unlock(String key, ILockSupportContext context) {
|
||||
log.info("开始尝试释放锁 {}", key);
|
||||
String requestId = IdThreadLocalHelper.get();
|
||||
log.info("开始尝试释放锁 requestId: {}", requestId);
|
||||
|
||||
final ICommonCacheService commonCacheService = context.commonCacheService();
|
||||
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
|
||||
Object result = commonCacheService.eval(script, Collections.singletonList(key), Collections.singletonList(requestId));
|
||||
return JedisConst.RELEASE_SUCCESS.equals(result);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package com.github.houbb.lock.core.support.simple;
|
||||
|
||||
import com.github.houbb.heaven.util.lang.StringUtil;
|
||||
import com.github.houbb.id.core.util.IdThreadLocalHelper;
|
||||
import com.github.houbb.lock.core.constant.LockConst;
|
||||
import com.github.houbb.lock.core.core.AbstractLock;
|
||||
import com.github.houbb.lock.core.exception.LockRuntimeException;
|
||||
|
||||
/**
|
||||
* 简单锁实现策略
|
||||
*
|
||||
* @author binbin.hou
|
||||
* @since 0.0.4
|
||||
*/
|
||||
public class SimpleLock extends AbstractLock {
|
||||
|
||||
public static SimpleLock newInstance() {
|
||||
return new SimpleLock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryLock(String key) {
|
||||
final String requestId = id.id();
|
||||
IdThreadLocalHelper.put(requestId);
|
||||
|
||||
return operator.lock(key, requestId, LockConst.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 LockRuntimeException("Thread " + threadName +" not contains requestId");
|
||||
}
|
||||
|
||||
boolean unlock = operator.unlock(key, requestId);
|
||||
if(!unlock) {
|
||||
throw new LockRuntimeException("Unlock key " + key + " result is failed!");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user