java redis分布式锁_Java实现基于Redis的分布式锁

packagecc.lixiaohui.lock;

importjava.util.concurrent.TimeUnit;

importredis.clients.jedis.Jedis;

/**

 
 

* 基于Redis的SETNX操作实现的分布式锁

*

* 获取锁时最好用lock(long time, TimeUnit unit), 以免网路问题而导致线程一直阻塞

*

* SETNC操作参考资料

*

* @author lixiaohui

*

*/

publicclassRedisBasedDistributedLockextendsAbstractLock {

privateJedis jedis;

// 锁的名字

protectedString lockKey;

// 锁的有效时长(毫秒)

protectedlonglockExpires;

publicRedisBasedDistributedLock(Jedis jedis, String lockKey,longlockExpires) {

this.jedis = jedis;

this.lockKey = lockKey;

this.lockExpires = lockExpires;

}

// 阻塞式获取锁的实现

protectedbooleanlock(booleanuseTimeout,longtime, TimeUnit unit,booleaninterrupt)throwsInterruptedException{

if(interrupt) {

checkInterruption();

}

longstart = System.currentTimeMillis();

longtimeout = unit.toMillis(time);// if !useTimeout, then it's useless

while(useTimeout ? isTimeout(start, timeout) :true) {

if(interrupt) {

checkInterruption();

}

longlockExpireTime = System.currentTimeMillis() + lockExpires +1;//锁超时时间

String stringOfLockExpireTime = String.valueOf(lockExpireTime);

if(jedis.setnx(lockKey, stringOfLockExpireTime) ==1) {// 获取到锁

// TODO 成功获取到锁, 设置相关标识

locked = true;

setExclusiveOwnerThread(Thread.currentThread());

returntrue;

}

String value = jedis.get(lockKey);

if(value !=null&& isTimeExpired(value)) {// lock is expired

// 假设多个线程(非单jvm)同时走到这里

String oldValue = jedis.getSet(lockKey, stringOfLockExpireTime); // getset is atomic

// 但是走到这里时每个线程拿到的oldValue肯定不可能一样(因为getset是原子性的)

// 加入拿到的oldValue依然是expired的,那么就说明拿到锁了

if(oldValue !=null&& isTimeExpired(oldValue)) {

// TODO 成功获取到锁, 设置相关标识

locked = true;

setExclusiveOwnerThread(Thread.currentThread());

returntrue;

}

} else{

// TODO lock is not expired, enter next loop retrying

}

}

returnfalse;

}

publicbooleantryLock() {

longlockExpireTime = System.currentTimeMillis() + lockExpires +1;//锁超时时间

String stringOfLockExpireTime = String.valueOf(lockExpireTime);

if(jedis.setnx(lockKey, stringOfLockExpireTime) ==1) {// 获取到锁

// TODO 成功获取到锁, 设置相关标识

locked = true;

setExclusiveOwnerThread(Thread.currentThread());

returntrue;

}

String value = jedis.get(lockKey);

if(value !=null&& isTimeExpired(value)) {// lock is expired

// 假设多个线程(非单jvm)同时走到这里

String oldValue = jedis.getSet(lockKey, stringOfLockExpireTime); // getset is atomic

// 但是走到这里时每个线程拿到的oldValue肯定不可能一样(因为getset是原子性的)

// 假如拿到的oldValue依然是expired的,那么就说明拿到锁了

if(oldValue !=null&& isTimeExpired(oldValue)) {

// TODO 成功获取到锁, 设置相关标识

locked = true;

setExclusiveOwnerThread(Thread.currentThread());

returntrue;

}

} else{

// TODO lock is not expired, enter next loop retrying

}

returnfalse;

}

/**

* Queries if this lock is held by any thread.

*

* @return {@code true} if any thread holds this lock and

*         {@code false} otherwise

*/

publicbooleanisLocked() {

if(locked) {

returntrue;

} else{

String value = jedis.get(lockKey);

// TODO 这里其实是有问题的, 想:当get方法返回value后, 假设这个value已经是过期的了,

// 而就在这瞬间, 另一个节点set了value, 这时锁是被别的线程(节点持有), 而接下来的判断

// 是检测不出这种情况的.不过这个问题应该不会导致其它的问题出现, 因为这个方法的目的本来就

// 不是同步控制, 它只是一种锁状态的报告.

return!isTimeExpired(value);

}

}

@Override

protectedvoidunlock0() {

// TODO 判断锁是否过期

String value = jedis.get(lockKey);

if(!isTimeExpired(value)) {

doUnlock();

}

}

privatevoidcheckInterruption()throwsInterruptedException {

if(Thread.currentThread().isInterrupted()) {

thrownewInterruptedException();

}

}

privatebooleanisTimeExpired(String value) {

returnLong.parseLong(value) 

}

privatebooleanisTimeout(longstart,longtimeout) {

returnstart + timeout > System.currentTimeMillis();

}

privatevoiddoUnlock() {

jedis.del(lockKey);

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值