SpringBoot使用Redis实现分布式锁
分布式锁说明
Java中的锁:当多个线程去访问共享数据时,防止一些操作被覆盖(并发问题),这个时候就需要用到抢锁机制,抢到锁的线程才能进行操作,其余线程等待锁释放并抢到锁才能进行操作,例如Sychonized,Lock等。
分布式锁和java中的锁最大的区别在于共享资源是由多个进程去访问,这时候线程之间的锁机制就无法起到作用了,所以就需要引入一些可以被所有服务都能访问的外部服务来让实现锁,例如数据库,Redis,Zookeeper等
SpringBoot中实现
maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
redis配置
spring.redis.hostName = 地址
spring.redis.port = 6379
spring.redis.password = pwd
spring.redis.enableTransactionSupport = false
java代码
package com.servingcloud.foreign.service.common.util;
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
/**
* @author pengdy
* @description: redis获取分布式锁
*/
@Component
public class RedisUtilExt {
/**
* 默认锁超时时间
*/
private final static long DEFAULT_TIMEOUT = 30000;
/**
* MD5加密密码
*/
private final static String PWD_KEY = "redis_lock";
@Resource(
name = "stringRedisTemplate"
)
private RedisTemplate<String, String> stringRedisTemplate;
public String getSortStr(Object obj){
String objStr = JSON.toJSONString(obj);
return MD5Util.generate(PWD_KEY,"1",objStr);
}
/**
* 获取redis锁
* @param key
* @return
*/
public boolean getLock(String key){
//value值为系统当前时间
if(stringRedisTemplate.opsForValue().setIfAbsent(key,String.valueOf(System.currentTimeMillis()))){
//设置超时时间 防止死锁
stringRedisTemplate.expire(key,DEFAULT_TIMEOUT,TimeUnit.MILLISECONDS);
return true;
}
//获取上锁时间 判断锁是否超时,超时则删除key(redis重启会造成重启时间内一些过期的key未被清理),防止死锁
String valueTime = stringRedisTemplate.opsForValue().get(key);
if(StringUtils.isNotEmpty(valueTime) && System.currentTimeMillis()-Long.parseLong(valueTime)>DEFAULT_TIMEOUT){
//释放锁 再次抢锁
unLock(key);
return getLock(key);
}
return false;
}
/**
* 释放锁
* @param key
*/
public void unLock(String key){
stringRedisTemplate.opsForValue().getOperations().delete(key);
}
}