redis分布式锁原理与实例
目录1 分布式锁的实现方式2 redis分布式锁的原理2.1 分布式锁的基本实现2.2 如何避免死锁2.3 解锁3 redis分布式锁实现示例4 验证4.1 创建redis连接池4.2 单线程验证4.3 多线程验证1 分布式锁的实现方式分布式锁常用的有三种实现方式:1)基于zookeeper的分布式锁;2)基于数据库的分布式锁;3)基于r...
·
目录
1 分布式锁的实现方式
分布式锁常用的有三种实现方式:
1)基于zookeeper的分布式锁;
2)基于数据库的分布式锁;
3)基于redis的分布式锁。
每一种分布式锁都有自己的优缺点,今天我们来介绍一下基于redis的分布式锁。
2 redis分布式锁的原理
2.1 分布式锁的基本实现
redis的存储结构是key-value形式的,并且redis的操作都是单线程执行的。基于这两点我们可以设置一个key来做多线程的竞争资源,线程拿到key就继续业务流程,拿不到就等待。使用redis加锁,实际上就是给key设置一个值:
set lock_key random_value NX
NX键不存在时,才对键进行操作。这样一个线程操作lock_key时,其他线程就需要等待,达到了加锁的目的。
但是如果一个线程一直持有锁,就会造成死锁的情况。那么如何规避死锁呢?
2.2 如何避免死锁
可以设置过期时间,比如设置过期时间为500毫秒:
set lock_key random_value NX PX 500
这样即使线程没有释放锁,到了过期时间lock_key也会自动被释放。其他线程就可以拿到锁了。
2.3 解锁
redis的解锁就是把key删除即可,但是删除的时候不能随便删,比如线程A不能删除线程B的key,这个时候value就起到作用了,random_value我们设置为随机值,每一个线程都生成一个随机值作为random_value,删除key的时候先判断随机值是否和本线程的一致,一致的才可以删除。
3 redis分布式锁实现示例
package rediscat;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.SetParams;
import java.util.Collections;
/**
* @ClassName RedisUtils
* @Description redis分布式锁实现
* @Author boy
* @Date 2019/11/8 2:24 PM
*/
public class RedisUtils {
private static final String LOCK_SUCCESS = "OK";//加锁成功
private static final Long UNLOCK_SUCCESS = 1L;//解锁成功
/*
* @Author boy
* @Description 加锁
* @Date 2019/11/8 8:20 PM
* @Param [jedis, key, value, expireTime]
* @return boolean
*/
public static boolean lockKey(Jedis jedis,String key,String value,int expireTime){
SetParams params = SetParams.setParams();
params.px(expireTime); //过期时间,单位是ms
params.nx();//意思是SET IF NOT EXIST,即当key不存在时,进行set操作;若key已经存在,则不做任何操作
String result = jedis.set(key,value, params);
if (LOCK_SUCCESS.equals(result)){
return true;
}
return false;
}
/*
* @Author boy
* @Description 解锁
* @Date 2019/11/8 8:21 PM
* @Param [jedis, lockKey, value]
* @return boolean
*/
public static boolean unLockKey(Jedis jedis, String lockKey, String value) {
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
Object result = jedis.eval(script, Collections.singletonList(lockKey),Collections.singletonList(value));
if (UNLOCK_SUCCESS.equals(result)) {
return true;
}
return false;
}
}
4 验证
4.1 创建redis连接池
package rediscat;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
/**
* @ClassName RedisClientService
* @Description TODO
* @Author boy
* @Date 2019/11/8 4:05 PM
*/
public class RedisClientService {
public static JedisPool pool = null;
static {
JedisPoolConfig config = new JedisPoolConfig();
// 设置最大连接数
config.setMaxTotal(500);
// 设置最大空闲数
config.setMaxIdle(100);
// 设置最大等待时间
config.setMaxWaitMillis(1000 * 100);
// 在borrow一个jedis实例时,是否需要验证,若为true,则所有jedis实例均是可用的
config.setTestOnBorrow(true);
pool = new JedisPool(config, "121.36.25.118", 6379, 300000);
}
}
4.2 单线程验证
package rediscat;
import redis.clients.jedis.Jedis;
import java.util.UUID;
/**
* @ClassName RedisTest
* @Description TODO
* @Author boy
* @Date 2019/11/8 4:24 PM
*/
public class RedisTest {
public void testLock(){
Jedis jedis = RedisClientService.pool.getResource();
String key = "lockKey";
String value = UUID.randomUUID().toString();
int expireTime = 100;
boolean b = RedisUtils.lockKey(jedis,key,value,expireTime);
System.out.println("加锁 " + value + " " + b);
jedis.close();
Jedis jedis1 = RedisClientService.pool.getResource();
boolean bb = RedisUtils.unLockKey(jedis,key,value);
System.out.println("解锁 " + value + " " + bb);
jedis1.close();
}
public static void main(String[] args){
for(int i=0;i<400;i++){
RedisTest redisTest = new RedisTest();
redisTest.testLock();
}
}
}
4.3 多线程验证
package rediscat;
/**
* @ClassName TaskThread
* @Description TODO
* @Author boy
* @Date 2019/11/8 8:27 PM
*/
public class TaskThread extends Thread {
private RedisTest redisTest;
public TaskThread(RedisTest redisTest) {
this.redisTest = redisTest;
}
@Override
public void run() {
try {
synchronized (this) {
redisTest.testLock();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
RedisTest service = new RedisTest();
for (int i = 0; i < 400; i++) {
TaskThread thread = new TaskThread(service);
thread.start();
}
}
}
更多推荐
已为社区贡献1条内容
所有评论(0)