<!--redis--> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>1.6.5.RELEASE</version> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.7.3</version> </dependency>
package com.cn.pinliang.common.util; import com.cn.pinliang.common.thread.PostponeTask; import com.google.common.collect.Lists; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import redis.clients.jedis.Jedis; import java.io.Serializable; import java.util.Collections; @Component public class DistributedLock { @Autowired private RedisTemplate<Serializable, Object> redisTemplate; private static final Long RELEASE_SUCCESS = 1L; private static final String LOCK_SUCCESS = "OK"; private static final String SET_IF_NOT_EXIST = "NX"; private static final String SET_WITH_EXPIRE_TIME = "EX"; // 解锁脚本(lua) private static final String RELEASE_LOCK_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; /** * 分布式锁 * @param key * @param value * @param expireTime 单位: 秒 * @return */ public boolean lock(String key, String value, long expireTime) { return redisTemplate.execute((RedisCallback<Boolean>) redisConnection -> { Jedis jedis = (Jedis) redisConnection.getNativeConnection(); String result = jedis.set(key, value, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime); if (LOCK_SUCCESS.equals(result)) { return Boolean.TRUE; } return Boolean.FALSE; }); } /** * 解锁 * @param key * @param value * @return */ public Boolean unLock(String key, String value) { return redisTemplate.execute((RedisCallback<Boolean>) redisConnection -> { Jedis jedis = (Jedis) redisConnection.getNativeConnection(); Object result = jedis.eval(RELEASE_LOCK_SCRIPT, Collections.singletonList(key), Collections.singletonList(value)); if (RELEASE_SUCCESS.equals(result)) { return Boolean.TRUE; } return Boolean.FALSE; }); } }
public JsonResult add() throws Exception { String key = "add_information_lock"; String value = RandomUtil.produceStringAndNumber(10); long expireTime = 10L; boolean lock = distributedLock.lock(key, value, expireTime); String threadName = Thread.currentThread().getName(); if (lock) { System.out.println(threadName " 获得锁..............................."); Thread.sleep(30000); distributedLock.unLock(key, value); System.out.println(threadName " 解锁了..............................."); } else { System.out.println(threadName " 未获取到锁..............................."); return JsonResult.fail("未获取到锁"); } return JsonResult.succeed(); }
package com.cn.pinliang.common.util; import com.cn.pinliang.common.thread.PostponeTask; import com.google.common.collect.Lists; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import redis.clients.jedis.Jedis; import java.io.Serializable; import java.util.Collections; @Component public class DistributedLock { @Autowired private RedisTemplate<Serializable, Object> redisTemplate; private static final Long RELEASE_SUCCESS = 1L; private static final Long POSTPONE_SUCCESS = 1L; private static final String LOCK_SUCCESS = "OK"; private static final String SET_IF_NOT_EXIST = "NX"; private static final String SET_WITH_EXPIRE_TIME = "EX"; // 解锁脚本(lua) private static final String RELEASE_LOCK_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; // 延时脚本 private static final String POSTPONE_LOCK_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('expire', KEYS[1], ARGV[2]) else return '0' end"; /** * 分布式锁 * @param key * @param value * @param expireTime 单位: 秒 * @return */ public boolean lock(String key, String value, long expireTime) { // 加锁 Boolean locked = redisTemplate.execute((RedisCallback<Boolean>) redisConnection -> { Jedis jedis = (Jedis) redisConnection.getNativeConnection(); String result = jedis.set(key, value, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime); if (LOCK_SUCCESS.equals(result)) { return Boolean.TRUE; } return Boolean.FALSE; }); if (locked) { // 加锁成功, 启动一个延时线程, 防止业务逻辑未执行完毕就因锁超时而使锁释放 PostponeTask postponeTask = new PostponeTask(key, value, expireTime, this); Thread thread = new Thread(postponeTask); thread.setDaemon(Boolean.TRUE); thread.start(); } return locked; } /** * 解锁 * @param key * @param value * @return */ public Boolean unLock(String key, String value) { return redisTemplate.execute((RedisCallback<Boolean>) redisConnection -> { Jedis jedis = (Jedis) redisConnection.getNativeConnection(); Object result = jedis.eval(RELEASE_LOCK_SCRIPT, Collections.singletonList(key), Collections.singletonList(value)); if (RELEASE_SUCCESS.equals(result)) { return Boolean.TRUE; } return Boolean.FALSE; }); } /** * 锁延时 * @param key * @param value * @param expireTime * @return */ public Boolean postpone(String key, String value, long expireTime) { return redisTemplate.execute((RedisCallback<Boolean>) redisConnection -> { Jedis jedis = (Jedis) redisConnection.getNativeConnection(); Object result = jedis.eval(POSTPONE_LOCK_SCRIPT, Lists.newArrayList(key), Lists.newArrayList(value, String.valueOf(expireTime))); if (POSTPONE_SUCCESS.equals(result)) { return Boolean.TRUE; } return Boolean.FALSE; }); } }
package com.cn.pinliang.common.thread; import com.cn.pinliang.common.util.DistributedLock; public class PostponeTask implements Runnable { private String key; private String value; private long expireTime; private boolean isRunning; private DistributedLock distributedLock; public PostponeTask() { } public PostponeTask(String key, String value, long expireTime, DistributedLock distributedLock) { this.key = key; this.value = value; this.expireTime = expireTime; this.isRunning = Boolean.TRUE; this.distributedLock = distributedLock; } @Override public void run() { long waitTime = expireTime * 1000 * 2 / 3;// 线程等待多长时间后执行 while (isRunning) { try { Thread.sleep(waitTime); if (distributedLock.postpone(key, value, expireTime)) { System.out.println("延时成功..........................................................."); } else { this.stop(); } } catch (Exception e) { e.printStackTrace(); } } } private void stop() { this.isRunning = Boolean.FALSE; } }