上一篇也说到了使用redis怎样实现锁机制,其实无外乎就以下几个点:

1.如何保证上锁和解锁同为自己的锁而不是其他线程的锁?

2.上锁之后线程停止,怎么解锁?

3.多个线程竞争同一个锁,如何保证只有一个线程抢到?

4.没有抢到锁的线程要怎么操作?

首先我们选用 RedisTemplate 来操作Redis,2.1.0 以上的版本,有了setIfAbsent ,意思是:如果键不存在则新增,存在则不改变已经有的值。

@Service
public class RedisService {

    @Resource
    private RedisTemplate redisTemplate;

    /**
     * 如果键不存在则新增,存在则不改变已经有的值。
     * expireTime :单位为秒
     *
     * @return; 新增成功返回 true,反之则 false
     */
    public Boolean setIfAbsent(final String key, Object value, Long expireTime) {
        return redisTemplate.opsForValue().setIfAbsent(key, value, expireTime, TimeUnit.SECONDS);
    }

}

没有工具类,就引入了@Service注解,核心就 getLock 和 unLock 两个,相信你看完就能自己回答上面那四个问题了。

**
 * @ClassName : RedisLock
 * @Author : Yanqiang
 * @Date : 2019/9/10
 * @Description :redis锁实现
 */
@Service
public class RedisLock {

    @Resource
    RedisService redisService;

    /**
     * 使用 redis获取锁
     * key : key
     * value   : value
     * expireTime  : key value在redis中的过期时间,防止死锁
     * timeOut : 获取锁的过期时间
     *
     * @return: 返回value,以便在解锁的时候,判断当前锁是否为此线程的锁
     */
    private String getLock(String key, String value, Long expireTime, Long timeOut) {
        //在timeOut内如果获取不到锁会一直尝试重试(借鉴自旋的思想),获取锁的时间超过timeOut,就返回null,
        while (timeOut - System.currentTimeMillis() > 0) {
            //setIfAbsent:如果不存在就新增,存在则不做任何操作
            Boolean lock = redisService.setIfAbsent("lock:" + key, value, expireTime);
            if (lock) {
                return value;
            }
        }
        return null;
    }

    /**
     * 解锁
     * key : key
     * value   : value
     */
    public Boolean unLock(String key, String value) {
        key = "lock:" + key;
        //读取value值,判断是否为当前线程的锁
        if (redisService.get(key).toString().equals(value)) {
            return redisService.remove(key);
        }
        return false;
    }

    /**
     * 次数
     */
    int n = 0;

    /**
     * 测试锁demo
     */
    public void seckill() {
        // 返回锁的value值,供释放锁时候进行判断
        String threadName = Thread.currentThread().getName();
        String key = "resource";
        String identifier = getLock(key, threadName, 5L, System.currentTimeMillis() + 10000);

        if (identifier != null) {
            System.out.println(identifier + " 获得了锁");
            System.out.println(n++);
            Boolean unLock = unLock(key, identifier);
            if (unLock) {
                System.out.println(identifier + " 释放了锁");
            } else {
                System.out.println(key + " 释放锁失败 --error");
            }
        } else {
            System.out.println(key + " 没有获得到锁 --error");
        }
        System.out.println("=====================================");
    }
}
09-11 20:48