java如何使用redis加鎖
java使用redis加鎖
編寫LockUtil工具類
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.connection.RedisStringCommands.SetOption; import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.types.Expiration; import org.springframework.stereotype.Service; ? /** ?* LockUtil <br> ?* ?*/ @Service public class LockUtil { ? ? ? @Autowired ? ? private RedisTemplate redisTemplate; ? ? ? @Autowired ? ? private StringRedisTemplate stringRedisTemplate; ? ? ? /** ? ? ?* @param lockKey 上鎖的key ? ? ?* @param lockSeconds 上鎖的秒數(shù) ? ? ?* @return ? ? ?*/ ? ? public boolean lock(String lockKey, int lockSeconds) { ? ? ? ? return (Boolean) redisTemplate.execute((RedisCallback) connection -> { ? ? ? ? ? ? byte[] key = lockKey.getBytes(); ? ? ? ? ? ? Boolean set = connection.set(key, key, Expiration.seconds(lockSeconds), SetOption.SET_IF_ABSENT); ? ? ? ? ? ? if (set == null) { ? ? ? ? ? ? ? ? return false; ? ? ? ? ? ? } ? ? ? ? ? ? return set; ? ? ? ? }); ? ? } ? ? ? public boolean isLock(String lockKey) { ? ? ? ? return stringRedisTemplate.opsForValue().get(lockKey)!=null; ? ? } ? ? ? ? public boolean clearLock(String lockKey){ ? ? ? ?return redisTemplate.delete(lockKey); ? ? } }
使用鎖
public abstract class AbstractTask { ? ? ? @Autowired ? ? private LockUtil lockUtil; ? ? ? /** ? ? ?* 獲取redis鎖的key ? ? ?* ? ? ?* @return ? ? ?*/ ? ? protected abstract String getLockKey(); ? ? ? protected boolean lock() { ? ? ? ? return lockUtil.lock(getLockKey(), 120); ? ? } ? ? ? protected boolean lockManual() { ? ? ? ? return lockUtil.lock(getLockKey(), 299); ? ? } ? ? ? protected boolean clearLock() { ? ? ? ? return lockUtil.clearLock(getLockKey()); ? ? } }
@Component @Slf4j @RefreshScope public class FileCapacityCountTask extends AbstractTask{ ? ? @Autowired ? ? private FileCapacityCountService fileCapacityCountService; ? ? ? ? ? @Scheduled(cron = "${batch.verification.schedule.capacity}") ? ? public void task(){ ? ? ? ? if (!lock()) { ? ? ? ? ? ? log.info("本實(shí)例無(wú)需執(zhí)行定時(shí)任務(wù)"); ? ? ? ? ? ? return; ? ? ? ? } ? ? ? ? fileCapacityCountService.fileCapacityCountTask(); ? ? } ? ? ? @Override ? ? protected String getLockKey() { ? ? ? ? String today = DateUtil.formatDate(new Date()); ? ? ? ? return FileCapacityCountTask.class.getSimpleName() + CommonConstant.APPLICATION_NAME + today; ? ? } }
redis鎖用法java代碼
由于redis是串行的,所以可以用redis實(shí)現(xiàn)鎖機(jī)制。
下方是java代碼
@Component @Slf4j public class RedisSingleLock { private final StringRedisTemplate redis; public SimpleDistributedLock(StringRedisTemplate redis) { this.redis = redis; } //這個(gè)方法,可以傳入key加鎖;多線程調(diào)用時(shí),只有1個(gè)能獲取鎖成功,其它線程則會(huì)進(jìn)入循環(huán),不停嘗試獲取鎖 public void lock(String key) { do { Boolean lockSuccess = redis.opsForValue().setIfAbsent(key, "1", 1, TimeUnit.DAYS); if (lockSuccess == null) { throw new IllegalStateException(); } if (!lockSuccess) { try { TimeUnit.MILLISECONDS.sleep(100); } catch (InterruptedException e) { log.error(e.getMessage(), e); } } else { break; } } while (true); } //這個(gè)方法,傳入key釋放鎖,當(dāng)持有鎖的線程執(zhí)行業(yè)務(wù)代碼完畢后調(diào)用,釋放這個(gè)鎖;上方某一個(gè)在lock方法中循環(huán)嘗試獲得鎖的線程可以獲得鎖,另外的線程則繼續(xù)循環(huán)等待 public void releaseLock(String key) { redis.delete(key); } //這個(gè)方法只嘗試獲取一次鎖,返回獲取結(jié)果 public boolean tryLock(String key) { Boolean lockSuccess = redis.opsForValue().setIfAbsent(key, "1", 1, TimeUnit.DAYS); if (lockSuccess == null) { throw new IllegalStateException(); } return lockSuccess; } }
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
springboot項(xiàng)目如何設(shè)置session的過期時(shí)間
這篇文章主要介紹了springboot項(xiàng)目如何設(shè)置session的過期時(shí)間,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01Java如何通過Socket同時(shí)發(fā)送文本和文件
這篇文章主要介紹了Java如何通過Socket同時(shí)發(fā)送文本和文件問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08SpringBoot Mybatis Plus公共字段自動(dòng)填充功能
這篇文章主要介紹了SpringBoot Mybatis Plus公共字段自動(dòng)填充功能的相關(guān)資料,需要的朋友可以參考下2017-04-04SpringBoot配置Email發(fā)送功能實(shí)例
本篇文章主要介紹了SpringBoot配置Email發(fā)送功能實(shí)例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧2017-04-04java.util.concurrent.ExecutionException 問題解決方法
這篇文章主要介紹了java.util.concurrent.ExecutionException 問題解決方法的相關(guān)資料,需要的朋友可以參考下2016-11-11springboot讀取nacos配置文件的實(shí)現(xiàn)
SpringBoot注冊(cè)服務(wù)到Nacos上,由Nacos來(lái)做服務(wù)的管理,本文主要介紹了springboot讀取nacos配置文件的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05Hibernate連接三種數(shù)據(jù)庫(kù)的配置文件
今天小編就為大家分享一篇關(guān)于Hibernate連接三種數(shù)據(jù)庫(kù)的配置文件,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-03-03