当前位置 : 主页 > 编程语言 > java >

时间锁

来源:互联网 收集:自由互联 发布时间:2021-06-28
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
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 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 RedisTemplate
 
   springRedisTemplate;

    /**
     * 锁
     *
     * @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;
    }
}
 
网友评论