redis实现分布式锁

为什么要用分布式锁

分布式锁的目的其实很简单,就是为了保证多台服务器在执行某一段代码时保证只有一台服务器执行。

为了保证分布式锁的可用性,至少要确保锁的实现要同时满足以下几点:

  1. 互斥性。在任何时刻,保证只有一个客户端持有锁。

  2. 不能出现死锁。如果在一个客户端持有锁的期间,这个客户端崩溃了,也要保证后续的其他客户端可以上锁。

  3. 保证上锁和解锁都是同一个客户端。

redis实现分布式锁

加锁:使用set扩展命令,key:锁标识,value:持有当前锁线程标识,NX是if not exists(如果不存在)的简写,PX:超时时间(毫秒)。

解锁:只有当前锁的持有者才可以执行删除操作,通过lua脚本保证了get和del命令执行的原子性操作。

# 加锁命令
set key value NX PX milliseconds
# setnx lock value1

# 解锁命令
if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end

代码实现

// 加锁
public boolean lockByLua(String lockKey, String requestId, int expireTime) {
	
	RedisCache cache = redisFactory.getRedisCacheInstance(name);
	String result = cache.set(lockKey,requestId, "NX", "PX", expireTime);
	if ("OK".equals(result)) {
		return true;
	}

	return false;
}
// 解锁
public boolean unLockByLua(String lockKey, String requestId) {
	Long success = 1L;
	RedisCache cache = redisFactory.getRedisCacheInstance(name);
	String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
	Object result = cache.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
	
	if (success.equals(result)) {
		return true;
	}
	return false;
}

缺点:

  1. 未实现可阻塞,可重入性,公平性。

  2. 未能解决锁超时并发执行,集群容错。

setnx手动实现,坑很多、代码较为复杂

redisson实现分布式锁

setnx虽好,但是实现起来毕竟太过麻烦,一不小心就可能陷入并发编程的陷阱中,那么有没有更加简单的实现方式呢?答案就是redisson

redisson提供了一系列较为完善的工具类,其中就包含了分布式锁。用redisson实现分布式锁的流程极为简单。

引入依赖

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.14.0</version>
</dependency>

创建Redission实例

@Bean
public RedissonClient redisson(){
    Config config = new Config();
    config.useSingleServer().setAddress("redis://127.0.0.1:6379");

    return Redisson.create(config);
}

编写分布式锁代码
Redisson分布式锁的主要原理非常简单,利用了lua脚本的原子性。 在分布式环境下产生并发问题的主要原因是三个操作并不是原子操作:

  1. 获取库存
  2. 扣减库存
  3. 写入库存 那么如果我们把三个操作合并为一个操作,在默认单线程的Redis中运行,是不会产生并发问题的。
@Autowired
private RedissonClient redissonClient;

@RequestMapping("/reduct_stock")
public void reductStock(){RLock lock = redissonClient.getLock("redisson:stockLock");
    try{
        //加锁
        lock.lock();
        String stock = stringRedisTemplate.opsForValue().get("stock");
        int stockNum = Integer.parseInt(stock);
        if(stockNum > 0){
            //设置库存减1
            int realStock = stockNum - 1;
            stringRedisTemplate.opsForValue().set("stock",realStock + "");
            System.out.println("设置库存" + realStock);
        }else{
            System.out.println("库存不足");
        }}catch(Exception e){
        e.printStackTrace();
    }finally {
        lock.unlock();
    }
}

redisson实现分布式锁,能够保证多实例下线程安全,代码简单可靠

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码上行舟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值