redis分布式锁

redis是做为缓存的主流选择,这里主要拿它和memcached比较一下:

redis是单线程模型,没有锁的概念,不存在资源竞争,对于同一key是原子操作;memcached是多线程模型。利用自身的cas操作实现锁的操作(等同与乐观所,每一个key对应会产生一个64bit的标记,当某个线程更新key的值是会比较这个标记有没有变化,有变化则放弃更新);

redis中有一个setnx函数(set if not exist,当且仅当 key 不存在,将 key 的值设为 value ,并返回1;若给定的 key 已经存在,则 SETNX 不做任何动作,并返回0),可以利用它来实现一个简单的分布式锁;核心代码如下:

public class RedisLock implements Lock {

@Autowired

protected StringRedisTemplate redisTemplate;

private static final Logger logger = Logger.getLogger(RedisLock.class);

// lock flag stored in redis
private static final String LOCKED = "TRUE";

// timeout(ms)
private static final long TIME_OUT = 30000;

// lock expire time(s)
public static final int EXPIRE = 60;

// private Jedis jedis;
private String key;

// state flag
private volatile boolean locked = false;

private static ConcurrentMap<String, RedisLock> map = Maps.newConcurrentMap();

public RedisLock(String key) {
this.key = "_LOCK_" + key;
redisTemplate = (StringRedisTemplate) ApplicationContextHolder.getBean("redisTemplate");
}

public static RedisLock getInstance(String key) {
return map.getOrDefault(key, new RedisLock(key));
}

public void lock(long timeout) {
long nano = System.nanoTime();
timeout *= 1000000;
final Random r = new Random();
try {
while ((System.nanoTime() - nano) < timeout) {
if (redisTemplate.getConnectionFactory().getConnection().setNX(key.getBytes(), LOCKED.getBytes())) {
redisTemplate.expire(key, EXPIRE, TimeUnit.SECONDS);
locked = true;
logger.debug("add RedisLock[" + key + "].");
break;
}
Thread.sleep(3, r.nextInt(500));
}
} catch (Exception e) {
}
}

@Override
public void unlock() {
if (locked) {
logger.debug("release RedisLock[" + key + "].");
redisTemplate.delete(key);
}
}

@Override
public void lock() {
lock(TIME_OUT);
}

@Override
public void lockInterruptibly() throws InterruptedException {

}

@Override
public Condition newCondition() {
return null;
}

@Override
public boolean tryLock() {
return false;
}

@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}
}

可以利用以上对象对共享资源进行锁定,功能类似于java内置锁ReentrantLock

其他常见用法:

if(getRedisClient().setnx("需要锁定的key", value)>0){
return "重复调用";
}

以上利用setnx的特性实现表单重复提交的问题。避免请求密集造成数据重复
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值