现在我们采用的系统都是分布式,比如我们Sychnized上锁,因为他是JVM层面的,所以如果是两台机器的话,这时候它就无能为力了,这时候我们可以用Reddisson。
1. 分布式锁的条件
- 互斥性
- 高效性
- 支持阻塞和非阻塞
- 支持公平锁和非公平锁
2. 实现分布式锁的方案
- .数据库实现(乐观锁)
- ZK(借鉴Node的临时顺序节点)
- Redission
3. Redission分布式锁原理
当线程1获取到锁以后,Redission底层有一个watch dog(看门口)会一直检测着,假如现线程1还持有锁,然后就会延长锁时间;这时候线程2来了一个,一直while循环,指导获取到锁;
源码认证:
<T> RFuture<T> tryLockInnerAsync(long leaseTime, TimeUnit unit, long threadId, RedisStrictCommand<T> command) {
internalLockLeaseTime = unit.toMillis(leaseTime);
return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, command,
"if (redis.call('exists', KEYS[1]) == 0) then " +
"redis.call('hset', KEYS[1], ARGV[2], 1); " +
"redis.call('pexpire', KEYS[1], ARGV[1]); " +
"return nil; " +
"end; " +
"if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then " +
"redis.call('hincrby', KEYS[1], ARGV[2], 1); " +
"redis.call('pexpire', KEYS[1], ARGV[1]); " +
"return nil; " +
"end; " +
"return redis.call('pttl', KEYS[1]);",
Collections.<Object>singletonList(getName()), internalLockLeaseTime, getLockName(threadId));
}
- KEYS[1] :获取的锁
- ARGV[2]::获取锁的那个线程
- ARGV[1]: 获取锁的时间
上面是一段lua脚本,其具体的意思是:
- 判断有key KEYS[1])是否存在
- 如果没有,则设定hash值,大key是KEYS[1]),value是键值对为“ARGV[2], 1)”,并且设定过期时间
- 如果存在,然后判断 大key–KEYS[1])下面的小key–ARGV[2]是否存在,如果存在,则在其值上加1,并且重新设定过期时间
- 返回过期时间;
4.场景应用
比如双11进行促销,商品在减库存的时候,我们可以进行运用;下面是一个小demo;
String product_002="stock";
//获取锁对象
RLock redissLock= redisson.getLock(product_002);
try {
//相当于:stringRedisTemplate.opsForValue().setIfAbsent(K key, V value, long timeout, TimeUnit unit);
//上锁
redissLock.lock();
int stock=Integer.parseInt(stringRedisTemplate.opsForValue().get(product_002));
if(stock>0){
stock=stock-1;
stringRedisTemplate.opsForValue().set(product_002,stock+"");
System.out.println("库存扣减成功:"+stock);
}else{
System.out.println("库存不足!");
}
}finally {
//redission 释放锁
redissLock.unlock();
}
return "end";
}
版权声明:本文为dfshsdr原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。