參考:https://www.cnblogs.com/technologykai/p/8658689.html
@Component public class RedisLockManager implements Lock { Logger logger = LoggerFactory.getLogger(RedisLockManager.class); @Autowired RedisTool redisManager; /** * 請求鎖的超時時間(ms) */ private final long TIME_OUT = 30000; /** * 鎖的有效時間(毫秒) */ private long expire = 15000; private String key; private String value; private volatile boolean isLocked = false; public void setKey(String key) { this.key = key; } public void setValue(String value) { this.value = value; } @Override public void lock() { //系統當前時間,毫秒 long nowTime = System.nanoTime(); //請求鎖超時時間,毫秒 long timeout = TIME_OUT * 1000000; ThreadLocalRandom random = ThreadLocalRandom.current(); try { while ((System.nanoTime() - nowTime) < timeout) { boolean flag = redisManager.tryGetDistributedLock(this.key, this.value, this.expire); if (flag) { isLocked = true; //上鎖成功結束請求 break; } Thread.sleep(3, random.nextInt(500)); } } catch (Exception e) { isLocked = false; logger.error(e.getMessage(), e); } } @Override public void unlock() { //釋放鎖 //不管請求鎖是否成功,只要已經上鎖,客戶端都會進行釋放鎖的操作 if (isLocked) { redisManager.releaseDistributedLock(this.key, this.value); this.isLocked = false; } } @Override public void lockInterruptibly() { // TODO Auto-generated method stub } @Override public boolean tryLock() { // TODO Auto-generated method stub return false; } @Override public boolean tryLock(long time, TimeUnit unit) { this.expire = unit.toMillis(time); this.lock(); return this.isLocked; } @Override public Condition newCondition() { // TODO Auto-generated method stub return null; } }
@Component
public class RedisTool {
@Autwire
Jedis jedis;
private final String LOCK_SUCCESS = "OK"; private final String SET_IF_NOT_EXIST = "NX"; private final String SET_WITH_EXPIRE_TIME = "PX"; /** * 嘗試獲取分佈式鎖 * @param jedis Redis客戶端 * @param lockKey 鎖 * @param requestId 請求標識 * @param expireTime 超期時間 * @return 是否獲取成功 */ public boolean tryGetDistributedLock(String lockKey, String requestId, int expireTime) { String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime); if (LOCK_SUCCESS.equals(result)) { return true; } return false; } private final Long RELEASE_SUCCESS = 1L; /** * 釋放分佈式鎖 * @param jedis Redis客戶端 * @param lockKey 鎖 * @param requestId 請求標識 * @return 是否釋放成功 */ public boolean releaseDistributedLock(String lockKey, String requestId) { 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(requestId)); if (RELEASE_SUCCESS.equals(result)) { return true; } return false; } }