上一篇也說到了使用redis怎樣實現鎖機制,其實無外乎就如下幾個點:redis
1.如何保證上鎖和解鎖同爲本身的鎖而不是其餘線程的鎖? 2.上鎖以後線程中止,怎麼解鎖? 3.多個線程競爭同一個鎖,如何保證只有一個線程搶到? 4.沒有搶到鎖的線程要怎麼操做?
首先咱們選用 RedisTemplate 來操做Redis,2.1.0 以上的版本,有了setIfAbsent ,意思是:若是鍵不存在則新增,存在則不改變已經有的值。ide
@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("====================================="); } }