吉安感知网项目-后端
xiebin
2026-01-06 d207a86cdf1ab52ef8cb7cd83bad8fceab8038cf
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
package org.sxkj.common.redis;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
 
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
 
 
/**
 * redis 集群共享锁
 *
 * @author raojiangang
 */
public class RedisLockUtils<P, R> {
    private static final Logger LOG = LoggerFactory.getLogger(RedisLockUtils.class);
 
    /**
     * 加锁超时时间,单位毫秒,
     * 30秒超时
     */
    private static final long LOCK_TIMEOUT = 30 * 1000;
 
    private RedisTemplate<String, String> primaryStringRedisTemplate;
 
    public RedisLockUtils(RedisTemplate redisTemplate) {
        this.primaryStringRedisTemplate = redisTemplate;
    }
 
 
 
    /**
     * 加锁
     * 取到锁加锁,取不到锁一直等待知道获得锁
     *
     * @param lockKey key
     * @return 时间毫秒
     */
    private synchronized long lock(String lockKey) {
        while (true) {
            //锁时间
            long lockTimeout = currentTimeForRedis() + LOCK_TIMEOUT + 1;
            if (serializerRedisKey(lockKey, lockTimeout)) {
 
                //设置超时时间,释放内存
                primaryStringRedisTemplate.expire(lockKey, LOCK_TIMEOUT, TimeUnit.MILLISECONDS);
                return lockTimeout;
            } else {
                //获取redis里面的时间
                Object result = primaryStringRedisTemplate.opsForValue().get(lockKey);
 
                Long currLockTimeoutStr = result == null ? null : Long.parseLong(result.toString());
                //锁已经失效
                if (currLockTimeoutStr != null && currLockTimeoutStr < System.currentTimeMillis()) {
                    Object andSet = primaryStringRedisTemplate.opsForValue().getAndSet(lockKey, Long.toString(lockTimeout));
                    Long oldLockTimeoutStr = Long.valueOf(
                            Objects.requireNonNull(
                                    andSet.toString())
                    );
                    if (oldLockTimeoutStr.equals(currLockTimeoutStr)) {
                        primaryStringRedisTemplate.expire(lockKey, LOCK_TIMEOUT, TimeUnit.MILLISECONDS);
 
                        return lockTimeout;
                    }
                }
            }
            try {
                TimeUnit.MILLISECONDS.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
 
    private Boolean serializerRedisKey(String lockKey, Long lockTimeout) {
        return primaryStringRedisTemplate.execute((RedisCallback<Boolean>) redisConnection -> {
            //定义序列化方式
            RedisSerializer<String> serializer = primaryStringRedisTemplate.getStringSerializer();
            byte[] value = serializer.serialize(lockTimeout.toString());
            return (boolean) redisConnection.setNX(lockKey.getBytes(), value);
        });
    }
 
    /**
     * 解锁
     *
     * @param lockKey   key
     * @param lockValue value
     */
    private synchronized void unlock(String lockKey, long lockValue) {
        LOG.info("==========执行解锁==========");
        //获取redis中设置的时间
        Object result = primaryStringRedisTemplate.opsForValue().get(lockKey);
        Long currentLockTimeoutStr = result == null ? null : Long.valueOf(result.toString());
 
        //如果是加锁者,则删除锁, 如果不是,则等待自动过期,重新竞争加锁
        if (currentLockTimeoutStr != null && currentLockTimeoutStr == lockValue) {
            primaryStringRedisTemplate.delete(lockKey);
            LOG.info("==========解锁成功==========");
        }
    }
 
    /**
     * 获取服务时间
     *
     * @return 时间戳
     */
    private long currentTimeForRedis() {
        return primaryStringRedisTemplate.execute(
                (RedisCallback<Long>) redisConnection -> redisConnection.time());
    }
 
 
    /**
     * redis 全局锁
     * 有参有返回值
     *
     * @param lockKey  key
     * @param function fun
     */
    public R tryLock(String lockKey, P param, Function<P, R> function) {
        R result = null;
        try {
            long lockTime = lock(lockKey);
            result = function.apply(param);
            //释放锁
            unlock(lockKey, lockTime);
        } catch (Exception e) {
            throw e;
        } finally {
            deleteKey(lockKey);
        }
        return result;
    }
 
    /**
     * redis 全局锁
     * 有参有返回值
     *
     * @param lockKey  key
     * @param function fun
     */
    public R tryLock(String lockKey, Supplier<R> function) {
        R result = null;
        try {
            long lockTime = lock(lockKey);
            result = function.get();
            //释放锁
            unlock(lockKey, lockTime);
        } catch (Exception e) {
            throw e;
        } finally {
            deleteKey(lockKey);
        }
        return result;
    }
 
    /**
     * redis 全局锁
     * 有参 无返回值
     *
     * @param lockKey  key
     * @param consumer fun
     */
    public void tryLock(String lockKey, P param, Consumer<P> consumer) {
        try {
            long lockTime = lock(lockKey);
            //执行
            consumer.accept(param);
            //释放锁
            unlock(lockKey, lockTime);
        } finally {
            deleteKey(lockKey);
        }
    }
 
    /**
     * redis 全局锁
     * 无参无返回值
     *
     * @param lockKey  key
     * @param runnable fun
     */
    public void tryLock(String lockKey, Runnable runnable) {
        try {
            long lockTime = lock(lockKey);
            //执行
            runnable.run();
            //释放锁
            unlock(lockKey, lockTime);
 
        } finally {
            deleteKey(lockKey);
        }
    }
 
    private void deleteKey(String lockKey) {
        primaryStringRedisTemplate.delete(lockKey);
    }
 
}