媒介
漫衍式锁一般有三种实现方法:1. 数据库乐观锁;2. 基于Redis的漫衍式锁;3. 基于ZooKeeper的漫衍式锁。本篇博客将先容第二种方法,基于Redis实现漫衍式锁。固然网上已经有各类先容Redis漫衍式锁实现的博客,然而他们的实现却有着各类百般的问题,为了制止误人后辈,本篇博客将具体先容如何正确地实现Redis漫衍式锁。
靠得住性
首先,为了确保漫衍式锁可用,我们至少要确保锁的实现同时满意以下四个条件:
代码实现
组件依赖
首先我们要通过Maven引入Jedis开源组件,在pom.xml文件插手下面的代码:
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency>
加锁代码
正确姿势
Talk is cheap, show me the code。先展示代码,再带各人逐步表明为什么这样实现:
public class RedisTool { private static final String LOCK_SUCCESS = "OK"; private static final String SET_IF_NOT_EXIST = "NX"; private static final String SET_WITH_EXPIRE_TIME = "PX"; /** * 实验获取漫衍式锁 * @param jedis Redis客户端 * @param lockKey 锁 * @param requestId 请求标识 * @param expireTime 超期时间 * @return 是否获取乐成 */ public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) { String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime); if (LOCK_SUCCESS.equals(result)) { return true; } return false; } }
可以看到,我们加锁就一行代码:jedis.set(String key, String value, String nxxx, String expx, int time),这个set()要领一共有五个形参:
总的来说,执行上面的set()要领就只会导致两种功效:1. 当前没有锁(key不存在),昆山软件公司,那么就举办加锁操纵,劳务派遣管理系统,并对锁配置个有效期,同时value暗示加锁的客户端。2. 已有锁存在,不做任何操纵。
心细的童鞋就会发明白,我们的加锁代码满意我们靠得住性里描写的三个条件。首先,set()插手了NX参数,可以担保假如已有key存在,则函数不会挪用乐成,也就是只有一个客户端能持有锁,满意互斥性。其次,由于我们对锁配置了逾期时间,纵然锁的持有者后续产生瓦解而没有解锁,锁也会因为到了逾期时间而自动解锁(即key被删除),不会发存亡锁。最后,因为我们将value赋值为requestId,代表加锁的客户端请求标识,那么在客户端在解锁的时候就可以举办校验是否是同一个客户端。由于我们只思量Redis单机陈设的场景,所以容错性我们暂不思量。
错误示例1
较量常见的错误示例就是利用jedis.setnx()和jedis.expire()组合实现加锁,代码如下:
public static void wrongGetLock1(Jedis jedis, String lockKey, String requestId, int expireTime) { Long result = jedis.setnx(lockKey, requestId); if (result == 1) { // 若在这里措施溘然瓦解,则无法配置逾期时间,将发存亡锁 jedis.expire(lockKey, expireTime); } }
setnx()要领浸染就是SET IF NOT EXIST,expire()要领就是给锁加一个逾期时间。乍一看仿佛和前面的set()要领功效一样,然而由于这是两条Redis呼吁,不具有原子性,假如措施在执行完setnx()之后溘然瓦解,昆山软件开发,导致锁没有配置逾期时间。那么将会发存亡锁。网上之所以有人这样实现,是因为低版本的jedis并不支持多参数的set()要领。
错误示例2