首先导入redis依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
然后配置redis:
spring:
redis:
host: 192.168.1.210
port: 6379
使用redis实现分布式主体代码:
@Autowired
StringRedisTemplate redisTemplate;
public String getDistributeResult() {
//1.占分布式锁
String uuid = UUID.randomUUID().toString();
Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", uuid, 300, TimeUnit.SECONDS);//保证锁的赋值和过期时间设置的原子性,同时过期时间避免出现死锁问题
if(lock){
System.out.println("获取分布式锁成功。。。");
//加锁成功...执行业务
String result = "";
try{
result = getResult();
}finally{
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
//删除锁
Long lock1 = redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), Arrays.asList("lock"), uuid);
}
return result;
}else{
try {
//休眠100ms重试
Thread.sleep(200);
} catch (InterruptedException e) {
}
return getDistributeResult();//自旋方式
}
}
public String getResult(){
return "ok";
}
lua脚本解锁(获取值并进行对比)也是为了避免客户端在过期时间后尝试释放锁,删除稍后获得锁的另一个客户端创建的,参考:SET | Redis
开发中经常会使用redisson代替上面繁琐的(容易遗漏的)分布式锁实现,大量节省了开发时间,让程序员把更多的精力放在业务开发上。
想要使用redisson首先要引入依赖(redis的也需要前面已经引入过了)
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.12.0</version>
</dependency>
创建redisson自定义配置类:
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.io.IOException;
@Configuration
public class MyRedissonConfig {
@Bean
public RedissonClient redisson() throws IOException {
//1.创建配置
Config config = new Config();
config.useSingleServer().setAddress("redis://192.168.1.210:6379");
RedissonClient redissonClient = Redisson.create(config);
return redissonClient;
}
}
然后就可以使用redisson了,如下:
@Autowired
RedissonClient redisson;
public String getResultWithRedissonLock() {
RLock lock = redisson.getLock("redisson-lock");
lock.lock();
String result = "";
try{
result = getResult();
}finally{
lock.unlock();
}
return result;
}
lock()加锁,unlock()释放锁,就是这么简单。
redisson的锁默认过期时间30s(LockWatchdogTimeout看门狗的默认时间),且支持自动续期(即业务执行未完成可以延长锁的过期时间),只要占锁成功,就会启动一个定时任务【重新给锁设置过期时间,新的过期时间就是看门狗的默认时间】,每隔10s(internalLockLeaseTime【看门狗时间】 / 3, 10s)都会自动再次续期,续成30s
如果我们设置了过期时间,那么就不会存在自动续期等操作,
lock.lock(10, TimeUnit.SECONDS);但是一定要保证自动解锁的时间要大于业务执行的时间。
同时redisson还支持多种锁机制,包含RReadWriteLock,RSemaphore,RCountDownLatch等
可以根据自己的业务场景使用不同的锁。