Fork me on GitHub

八.浅谈redis分布式锁

基础部分

这一节都是自己瞎了解,反正自己觉得总得先知道这是个怎么回事,最后自己再研究的时候,也不至于瞎搞

JedisPoolUtils

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

/**
* @author RickYinPeng
* @ClassName JedisPoolUtils
* @Description jedis获取连接工具类
* @date 2018/10/31/20:42
*/
public class JedisPoolUtils {

private static JedisPool pool = null;

static {
//加载配置文件
InputStream inputStream = JedisPoolUtils.class.getClassLoader().getResourceAsStream("redis.properties");
Properties properties = new Properties();
try {
properties.load(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
//0、创建池子的配置对象
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();

//最大闲置个数,当闲置超过30个的时候就开始关闭一些连接
jedisPoolConfig.setMaxIdle(Integer.valueOf(properties.get("redis.maxIdle").toString()));

//最小闲置个数,最小闲置的连接个数
/*jedisPoolConfig.setMinIdle(Integer.valueOf(properties.get("redis.minIdle").toString()));*/

//最大连接数,超过50个就没了
jedisPoolConfig.setMaxTotal(Integer.valueOf(properties.get("redis.maxTotal").toString()));

//1、创建一个redis的连接池
pool = new JedisPool(jedisPoolConfig, (String) properties.get("redis.url"), Integer.valueOf(properties.get("redis.port").toString()));
}

//获得jedis资源的方法
public static Jedis getJedis(){
return pool.getResource();
}

/**
* 释放Redis客户端连接
*/
public static void releaseResource(JedisPool jedisPool,Jedis jedis){
if(jedisPool !=null && jedis!=null){
jedisPool.returnResource(jedis);
}
}
public static void main(String[] args) {
Jedis jedis = getJedis();
System.out.println(jedis.get("xxx"));
}
}

redis.properties

1
2
3
4
5
redis.maxIdle=5
redis.minIdle=10
redis.maxTotal=300
redis.url=192.168.25.128
redis.port=6379

锁接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* getLock(); 获取锁
* releaselock; 释放锁
*/
public interface Lock {
/**
* setNx(Key key,)
* @param key
* @return
*/
public String getLock(String key,int timeout,int expire);

/**
* true:释放成功
* false:释放失败
* @return
*/
public boolean releaselock(String key,String value);
}

锁实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;

import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
* @author RickYinPeng
* @ClassName RedisDistributedLock
* @Description
* @date 2019/1/27/20:49
*/
public class RedisDistributedLock implements Lock {

/**
* 获取锁:
* 1:setNx 去创建一个键值对的数据,看是否可以操作命令?返回为true:可以操作,key为null
* 2:争抢创建key的权限(锁对象)
* 3:争抢创建key成功之后,其他的线程都不能进来,通过锁对象的值(唯一值)进行校验
* 4:第三方因素,客户端挂了,超时,网络因素
*/
@Override
public String getLock(String lockName, int timeoutT, int expire) {
/**
* 能连接上redis服务器,才能操作setNx
*/
Jedis jedis = null;

try {
jedis = JedisPoolUtils.getJedis();
/**
* 锁对象的值key-----value(唯一) 重入
*/
//3000年内都没办法重复的唯一值
String value = UUID.randomUUID().toString();

//11123123+timeout
long endTime = System.currentTimeMillis() + timeoutT;

/**
* 在上面那个时间戳之前都可以去尝试setNx
*/
while (System.currentTimeMillis() < endTime) {
if (jedis.setnx(lockName, value) == 1) {
//设置成功
if (jedis.ttl(lockName) == -1) {
jedis.expire(lockName, expire);
}
//返回锁的值
return value;
}
TimeUnit.MICROSECONDS.sleep(500);
}
} catch (Exception e) {
try {
throw e;
} catch (InterruptedException e1) {
e1.printStackTrace();
}
} finally {
if (jedis != null) {
jedis.close();
}
}

return null;
}

/**
* 1:redis的分布式锁必须由获取该分布式锁对象的客户端去释放
* 2:lockName ----> value --->uuid 去区别是不是这个客户端
*/
@Override
public boolean releaselock(String lockName, String value) {
//拥有jedis,我们才能去操作服务器的释放
Jedis client = JedisPoolUtils.getJedis();
try {
/**
* 释放锁
*/
while (client.exists(lockName)){
client.watch(lockName);
//释放条件
if(value.equals(client.get(lockName))){
//启动Redis本身的事务
Transaction transaction = client.multi();
transaction.del(lockName);
//提交事务
List<Object> exec = transaction.exec();
if(exec==null){
continue;
}
return true;
}
client.unwatch();
break;
}
}catch (Exception e){
//异常出栈
e.printStackTrace();
}finally {
if (client != null) {
client.close();
}
}
return false;
}
}

image

image

image

image

image

image

image