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 { private static final Logger LOG = LoggerFactory.getLogger(RedisLockUtils.class); /** * 加锁超时时间,单位毫秒, * 30秒超时 */ private static final long LOCK_TIMEOUT = 30 * 1000; private RedisTemplate 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) redisConnection -> { //定义序列化方式 RedisSerializer 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) redisConnection -> redisConnection.time()); } /** * redis 全局锁 * 有参有返回值 * * @param lockKey key * @param function fun */ public R tryLock(String lockKey, P param, Function 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 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

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); } }