public class RedisLockImplimplements RedisDistributionLock {
// 加鎖超時時間,單位毫秒, 即:加鎖時間內(nèi)執(zhí)行完操作,如果未完成會有并發(fā)現(xiàn)象
? private static final long LOCK_TIMEOUT =5 *1000;
? private static final LoggerLOG = LoggerFactory.getLogger(RedisLockImpl.class);
? @Autowired
? private StringRedisTemplateredisTemplate;
? /**
* 加鎖 取到鎖加鎖,取不到鎖一直等待知道獲得鎖
*
? ? * @param lockKey
? ? * @param threadName
? ? * @return
? ? */
? @Override
? public synchronized long lock(String lockKey, String threadName) {
LOG.info(threadName+"開始執(zhí)行加鎖");
? ? ? while (true) {// 循環(huán)獲取鎖
// 鎖時間
? ? ? ? Long lock_timeout = currtTimeForRedis() +LOCK_TIMEOUT +1;
? ? ? ? Boolean execute =redisTemplate.execute(new RedisCallback() {
@Override
? ? ? ? ? ? public BooleandoInRedis(RedisConnection redisConnection)throws DataAccessException {
// 定義序列化方式
? ? ? ? ? ? ? RedisSerializer serializer =redisTemplate.getStringSerializer();
? ? ? ? ? ? ? byte[] value = serializer.serialize(lock_timeout.toString());
? ? ? ? ? ? ? boolean flag = redisConnection.setNX(lockKey.getBytes(), value);
? ? ? ? ? ? ? return flag;
? ? ? ? ? ? }
});
? ? ? ? if (execute) {
// 如果加鎖成功
? ? ? ? ? ? LOG.info(threadName +"加鎖成功 ++++ 111111");
? ? ? ? ? ? // 設(shè)置超時時間,釋放內(nèi)存
? ? ? ? ? ? redisTemplate.expire(lockKey, LOCK_TIMEOUT *2, TimeUnit.MILLISECONDS);
? ? ? ? ? ? return lock_timeout;
? ? ? ? }else {
// 獲取redis里面的時間
? ? ? ? ? ? String result =redisTemplate.opsForValue().get(lockKey);
? ? ? ? ? ? Long currt_lock_timeout_str = result ==null ?null : Long.parseLong(result);
? ? ? ? ? ? long s = currt_lock_timeout_str - currtTimeForRedis();
? ? ? ? ? ? LOG.info("currt_lock_timeout_str:"+currt_lock_timeout_str+"---"+s);
? ? ? ? ? ? // 鎖已經(jīng)失效
? ? ? ? ? ? if (currt_lock_timeout_str !=null && s <0) {
// 判斷是否為空,不為空時,說明已經(jīng)失效,如果被其他線程設(shè)置了值,則第二個條件判斷無法執(zhí)行
// 獲取上一個鎖到期時間,并設(shè)置現(xiàn)在的鎖到期時間
? ? ? ? ? ? ? Long old_lock_timeout_Str = Long
.valueOf(redisTemplate.opsForValue().getAndSet(lockKey, lock_timeout.toString()));
? ? ? ? ? ? ? LOG.info("currt_lock_timeout_str:"+currt_lock_timeout_str+"old_lock_timeout_Str:"+old_lock_timeout_Str);
? ? ? ? ? ? ? if (old_lock_timeout_Str !=null && old_lock_timeout_Str.equals(currt_lock_timeout_str)) {
// 多線程運(yùn)行時,多個線程簽好都到了這里,但只有一個線程的設(shè)置值和當(dāng)前值相同,它才有權(quán)利獲取鎖
? ? ? ? ? ? ? ? ? LOG.info(threadName +"加鎖成功 ++++ 22222");
? ? ? ? ? ? ? ? ? // 設(shè)置超時間,釋放內(nèi)存
? ? ? ? ? ? ? ? ? redisTemplate.expire(lockKey, LOCK_TIMEOUT, TimeUnit.MILLISECONDS);
? ? ? ? ? ? ? ? ? // 返回加鎖時間
? ? ? ? ? ? ? ? ? return lock_timeout;
? ? ? ? ? ? ? }
}
}
try {
LOG.info(threadName +"等待加鎖, 睡眠200毫秒");
? ? ? ? ? ? // TimeUnit.MILLISECONDS.sleep(100);
? ? ? ? ? ? TimeUnit.MILLISECONDS.sleep(200);
? ? ? ? }catch (InterruptedException e) {
e.printStackTrace();
? ? ? ? }
}
}
/**
* 解鎖
* 這里不需要synchronized,方法級是class對象加鎖
? ? * @param lockKey
? ? * @param lockValue
? ? * @param threadName
? ? */
? @Override
? public void unlock(String lockKey, long lockValue, String threadName) {
LOG.info(threadName +"執(zhí)行解鎖==========");//正常直接刪除 如果異常關(guān)閉判斷加鎖會判斷過期時間
// 獲取redis中設(shè)置的時間
? ? ? String result =redisTemplate.opsForValue().get(lockKey);
? ? ? Long currt_lock_timeout_str = result ==null ?null : Long.valueOf(result);
? ? ? // 如果是加鎖者,則刪除鎖, 如果不是,則等待自動過期,重新競爭加鎖
? ? ? if (currt_lock_timeout_str !=null && currt_lock_timeout_str == lockValue) {
redisTemplate.delete(lockKey);
? ? ? ? LOG.info(threadName +"解鎖成功------------------");
? ? ? }else {
LOG.info(threadName +"鎖已被替換------------------");
? ? ? }
}
/**
* 多服務(wù)器集群,使用下面的方法,代替System.currentTimeMillis(),獲取redis時間,避免多服務(wù)的時間不一致問題?。?!
*
? ? * @return
? ? */
? @Override
? public long currtTimeForRedis() {
return redisTemplate.execute(new RedisCallback() {
@Override
? ? ? ? public LongdoInRedis(RedisConnection redisConnection)throws DataAccessException {
return redisConnection.time();
? ? ? ? }
});
? }