java利用redis實現(xiàn)分布式鎖,生產(chǎn)環(huán)境已驗證

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();

? ? ? ? }

});

? }

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容