实现分布式锁的几种方式:
- 数据库锁:性能不好,效率低。
- Redis分布式锁(setnx):setnx存入key如果存入成功返回1,如果key已经存在返回0,只要谁创建key成功,谁就能获取到锁。redis执行完操作的时候删除key释放锁,如果删除失败,就释放锁失败了。所以最好的办法是给key设置有效期,避免死锁。
redis分布式锁的核心方法:
- 获取锁(参数:1.获取锁之前的超时时间2.获取锁之后的超时时间)
- 获取锁的步骤可以总结为:
- 建立redis
- 生成value
- 定义锁名称
- 定义过期时间
- 定义在获取锁之前,获取的超时时间
- 使用setnx设置锁值
- 释放锁
- 释放锁的两种方式:
- key自动过期
-
public String lockWithTimeout(String lockKey, Long acquireTimeout, Long timeOut) { Jedis conn = null; String retIdentifierValue = null; try { // 1.建立redis连接 conn = jedisPool.getResource(); // 2.随机生成一个value String identifierValue = UUID.randomUUID().toString(); // 3.定义锁的名称 String lockName = "redis_lock" + lockKey; // 4.定义上锁成功之后,锁的超时时间 int expireLock = (int) (timeOut / 1000); // 5.定义在没有获取锁之前,锁的超时时间 Long endTime = System.currentTimeMillis() + acquireTimeout; while (System.currentTimeMillis() < endTime) { // 6.使用setnx方法设置锁值 if (conn.setnx(lockName, identifierValue) == 1) { // 7.判断返回结果如果为1,则可以成功获取锁,并且设置锁的超时时间 conn.expire(lockName, expireLock); retIdentifierValue = identifierValue; return retIdentifierValue; } // 8.否则情况下继续循环等待 } } catch (Exception e) { e.printStackTrace(); } finally { if (conn != null) { conn.close(); } } return retIdentifierValue; }
会遇到的两个超时问题:- 在规定时间内还没有获取锁,直接放弃。
- 获取锁成功后,对应的key的有效期,对应的key,在规定的时间内失效。
时间戳和uuid在redis分布式锁中最好不要用吧。