一个纯的java-redis锁,因为有更好的,暂时就只记录一下

找了很长时间,左试右试的搞了一个redis锁出来,但是被一个更好的方案取代了,有点郁闷,在此记录一下。

开始是因为redis的操作原子性问题,没有用redis自带的key过期,因为setnx 和expire是两个方法,无法保持强一致性,在高并发时候是致命的。而且保留着对redis的自带过期的不信任(这里补充一下,查了资料后发现redis的自带过期还是不错的,两种过期方式,一个是在get的时候判断key是否过期,一个是在空闲时间流出25%cpu时间随机拿带过期的key进行随机淘汰。不过可能在超大的吞吐量的时候可能会因为淘汰不及时,稍微占点内存),就选择了利用value来实现。

@Component
public class NamedLock {

    private static final int AUTO_RELEASE_AFTER_MINUTES = 10;
    @Autowired
    private RedisTemplate redisTemplate;

    public boolean tryLock(String name,long useless) {
        DateTime now = DateTime.now();
        Boolean tryLock = redisTemplate.opsForValue().setIfAbsent(name, now.getMillis());
        if (tryLock) {
            return true;
        } else {
            Long lockTime = (Long) redisTemplate.opsForValue().get(name);
            if (lockTime == null) {
                return redisTemplate.opsForValue().setIfAbsent(name, now.getMillis());
            }
            if (now.minusMinutes(AUTO_RELEASE_AFTER_MINUTES).isAfter(lockTime)) {
                Long originTime = (Long) redisTemplate.opsForValue().getAndSet(name, now.getMillis());
                if (originTime == null || originTime.equals(lockTime))
                    return true;
                else
                    return false;
            } else {
                return false;
            }
        }
    }

    public boolean isLocked(String name) {
        return redisTemplate.opsForValue().get(name) == null;
    }

    public void releaseLock(String name) {
        Long lockTime = (Long) redisTemplate.opsForValue().get(name);
        if(lockTime != null && DateTime.now().minusMinutes(AUTO_RELEASE_AFTER_MINUTES).isBefore(lockTime)){
            redisTemplate.delete(name);
        }
        return;
    }
}
不过后来大神从spring的git里找来一个好方法,就是利用redistemplate的execute,把命令当脚本执行,保证了redis 的setnx和过期的原子性,直接我这个方案就不合适了。还是要多了解api啊。

你可能感兴趣的:(redis锁,Java)