上一篇也说到了使用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("====================================="); } }