因为Java中的锁,只作用于单个JVM实例上。而当下在互联网技术架构中,大家都用的分布式架构了,应用部署到多个服务器,这种情况下,线程之间的锁机制,就没作用了。为了解决这个问题,我们就引入分布式锁。
(1)排他性:在同一时间只会有一个客户端能获取到锁,其它客户端无法同时获取。
(2)避免死锁:这把锁在一段有限的时间之后,一定会被释放。
(3)高可用:获取或释放锁的机制必须高可用且性能佳。
这里只讲基于Redis实现的分布式锁,需要引入Redisson。
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>${redisson.version}</version>
</dependency>
@Configuration
public class RedissonConfig {
@Value("${spring.redis.host}")
private String address;
@Value("${spring.redis.port}")
private String port;
@Value("${spring.redis.password}")
private String password;
@Value("${spring.redis.database}")
private Integer database;
@Bean(destroyMethod = "shutdown")
public RedissonClient redissonClient() {
Config config = new Config();
address = StringUtils.strip(address.trim(), ",");
String[] addressList = address.split(",");
if (addressList.length == 1) {
config.useSingleServer().setDatabase(database).setAddress("redis://" + addressList[0] + ":" + port);
if (StringUtils.isNotEmpty(password)) {
config.useSingleServer().setPassword(password);
}
} else {
ClusterServersConfig clusterServersConfig = config.useClusterServers().setScanInterval(2000);
for (String address : addressList) {
clusterServersConfig.addNodeAddress("redis://" + address + ":" + port);
if (StringUtils.isNotEmpty(password)) {
clusterServersConfig.setPassword(password);
}
}
}
return Redisson.create(config);
}
}
spring:
redis:
host: 127.0.0.1
port: 6379
password:
database: 0 # Redis数据库索引(默认为0)
lettuce:
pool:
max-active: 8 # 连接池最大连接数(使用负值表示没有限制) (默认为8)
max-wait: 0 # 连接池最大阻塞等待时间(使用负值表示没有限制) (默认为-1)
max-idle: 8 # 连接池中的最大空闲连接 (默认为8)
min-idle: 0 # 连接池中的最小空闲连接 (默认为0)
public interface RedisOpService {
Boolean isLocked(String lockName);
Boolean lock(String lockName);
Boolean unlock(String lockName);
}
@Service
@Slf4j
public class RedisOpServiceImpl implements RedisOpService {
@Resource
private RedissonClient redissonClient;
@Override
public Boolean isLocked(String lockName) {
RLock rLock = redissonClient.getLock(lockName);
return rLock.isLocked();
}
@Override
public Boolean lock(String lockName) {
try {
RLock rLock = redissonClient.getLock(lockName);
// 锁一段时间后自动释放,防止死锁
rLock.lock(10, TimeUnit.SECONDS);
log.info("RedisLock lock [{}] success", lockName);
} catch (Exception e) {
log.error("RedisLock lock [{}] Exception:", lockName, e);
return false;
}
return true;
}
@Override
public Boolean unlock(String lockName) {
try {
RLock rLock = redissonClient.getLock(lockName);
rLock.unlock();
log.info("RedisLock unlock [{}] success", lockName);
} catch (Exception e) {
log.error("RedisLock unlock [{}] Exception:", lockName, e);
return false;
}
return true;
}
}
@RestController
@Slf4j
public class RedisController {
@Resource
private RedisOpService redisOpService;
@GetMapping("test")
public void test() {
// 分布式锁处理,情况1:有竞争时,后面的请求报错丢弃,及时响应消息“请稍后重试”
String lockName = "test:" + 666;
if (redisOpService.isLocked(lockName)) {
throw new RuntimeException("请稍后重试");
}
try {
if (redisOpService.lock(lockName)) {
log.info("执行业务逻辑");
}
} catch (Exception e) {
log.error("异常", e);
} finally {
redisOpService.unlock(lockName);
}
}
@GetMapping("test2")
public void test2() {
// 分布式锁处理,情况2:有竞争时,阻塞等待,依次获取锁->执行->释放锁,直到都处理完成
String lockName = "test:" + 777;
try {
if (redisOpService.lock(lockName)) {
log.info("执行业务逻辑");
}
} catch (Exception e) {
log.error("异常", e);
} finally {
redisOpService.unlock(lockName);
}
}
}
两种应用场景:
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/sinat_27933301/article/details/121539636
内容来源于网络,如有侵权,请联系作者删除!