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 上鎖的秒數
     * @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("本實例無需執行定時任務");
            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實現鎖機制。

下方是java代碼

@Component
@Slf4j
public class RedisSingleLock {
    private final StringRedisTemplate redis;

    public SimpleDistributedLock(StringRedisTemplate redis) {
        this.redis = redis;
    }

    //這個方法,可以傳入key加鎖;多線程調用時,隻有1個能獲取鎖成功,其它線程則會進入循環,不停嘗試獲取鎖
    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);
    }

    //這個方法,傳入key釋放鎖,當持有鎖的線程執行業務代碼完畢後調用,釋放這個鎖;上方某一個在lock方法中循環嘗試獲得鎖的線程可以獲得鎖,另外的線程則繼續循環等待
    public void releaseLock(String key) {
        redis.delete(key);
    }
	
	//這個方法隻嘗試獲取一次鎖,返回獲取結果
    public boolean tryLock(String key) {
        Boolean lockSuccess = redis.opsForValue().setIfAbsent(key, "1", 1, TimeUnit.DAYS);
        if (lockSuccess == null) {
            throw new IllegalStateException();
        }

        return lockSuccess;
    }
}

    

總結

以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。

推薦閱讀: