gistfile1.txt import com.meallink.core.exception.api.LockException;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.stereotype.Component;import
import com.meallink.core.exception.api.LockException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import java.util.concurrent.TimeUnit; import static java.lang.System.currentTimeMillis; @Component public class LockUtils { /** * 最长时间锁为5分钟 */ private final static int maxExpireTime = 5 * 60; /** * 系统时间偏移量5秒,服务器间的系统时间差不可以超过5秒,避免由于时间差造成错误的解锁 */ private final static int offsetTime = 5; @Autowired private RedisTemplatespringRedisTemplate; /** * 锁 * * @param key key * @param waitTime 秒 - 最大等待时间,如果还无法获取,则直接失败 * @param expire 秒- 锁生命周期时间 * @return true 成功 false失败 * @throws Exception */ public boolean lock(String key, int waitTime, int expire) { long start = currentTimeMillis(); String lock_key = "lock_" + key; do { try { if (!springRedisTemplate.hasKey(lock_key)) { Long currentTime = System.currentTimeMillis(); springRedisTemplate.opsForValue().set(lock_key, currentTime, (expire > maxExpireTime) ? maxExpireTime : expire, TimeUnit.SECONDS); return true; } else { // 存在锁,并对死锁进行修复 // 上次锁时间 long lastLockTime = springRedisTemplate.opsForValue().get(lock_key); // 明确死锁,,再次设定一个合理的解锁时间让系统正常解锁 if (System.currentTimeMillis() - lastLockTime > (expire + offsetTime) * 1000) { // 原子操作,只需要一次,【任然会发生小概率事件,多个服务同时发现死锁同时执行此行代码(并发), // 为什么设置解锁时间为expire(而不是更小的时间),防止在解锁发送错乱造成新锁解锁】 springRedisTemplate.opsForValue().set(lock_key, 999999999L, expire); } } if (waitTime>0) { Thread.sleep(500); } } catch (Exception ex) { throw new LockException(); } } while (waitTime > 0 && (currentTimeMillis() - start) < waitTime * 1000); return false; } /** * 解锁 * * @param key * @return * @throws Exception */ public boolean unlock(String key) { String lock_key = "lock_" + key; try { springRedisTemplate.delete(lock_key); } catch (Exception ex) { throw ex; } return true; } }