没有合适的资源?快使用搜索试试~ 我知道了~
首页Java基于redis实现分布式锁代码实例
资源详情
资源评论
资源推荐

Java基于基于redis实现分布式锁代码实例实现分布式锁代码实例
主要介绍了Java基于redis实现分布式锁代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具
有一定的参考学习价值,需要的朋友可以参考下
为什么会有这个需求:
例如一个简单用户的操作,一个线程去修改用户状态,首先在在内存中读出用户的状态,然后在内存中进行修改,然后在存到
数据库中。在单线程中,这是没有问题的。但是在多线程中由于读取,修改,写入是三个操作,不是原子操作(同时成功或失
败),因此在多线程中会存在数据的安全性问题。
这个问题的话,就可以用分布式锁在限制程序的并发执行。
实现思路:
就是进来一个先占位,当别的线程进来操作的时候,发现有人占位了,就会放弃或者稍后再试。
占位的实现:
在redis中的setnx命令来实现,redis命令可以参考我这篇博客https://www.cnblogs.com/javazl/p/12657280.html,默认set命令
就是存值,当key存在的时候,set就会覆盖key的value值,而setnx则不会。当没有key的时候,setnx就会进来先占位,当key
存在了,其他的setnx就进不来了。。等到第一个执行完成后,在del命令释放位子。
代码实现:
public class LockTest {
public static void main(String[] args) {
Redis redis = new Redis();
redis.execute(jedis->{
Long setnx = jedis.setnx("k1", "v1");
//setnx的返回值为long类型
if (setnx == 1) {
//没人占位
jedis.set("name", "zl");
String name = jedis.get("name");
System.out.println(name);
//释放资源
jedis.del("k1");
}else{
//有人占位,停止/暂缓 操作
}
});
}
}
上边代码中,就是一个简易的分布式锁的实现,但是有一个问题。就是如果在占位后释放前挂了。那么这个线程会一直释放不
了,也就是del命令没有调用,后面的全部请求都阻塞到这里,锁就变成了死锁。因此这里需要去优化。
优化的方法就是加过期时间,确保锁在一定时间后能够释放.
public class LockTest {
public static void main(String[] args) {
Redis redis = new Redis();
redis.execute(jedis->{
Long setnx = jedis.setnx("k1", "v1");
if (setnx == 1) {
//给锁添加一个过期时间,防止应用在运行过程中抛出异常导致锁无法及时得到释放
jedis.expire("k1", 5);
//没人占位
jedis.set("name", "zl");
String name = jedis.get("name");
System.out.println(name);
jedis.del("k1");
}else{
//有人占位,停止/暂缓 操作
}
});
}
这样处理后,就可以保证锁可以正常的释放。但是会有一个新的问题,就是如果在取锁和设置过期时间服务器挂掉了,因为取
锁,也就是setnx和设置过期时间是两个操作,不具备原子性所以不可能同时完成。这个锁就会被一直占用,无法得到释放,
成为死锁。那么如何解决呢?
在redis2.8之后,setnx和expireke可以通过一个命令一起执行,让两个操作变成一个,就会解决这个问题。















安全验证
文档复制为VIP权益,开通VIP直接复制

评论0