问题背景
在一个订单匹配项目中,以网约车为例,当一个司机能够接单时,同时有多个乘客下单,此时只能有一个乘客能够匹配到该司机。
解决思路
单机解决思路
- 利用
synchronized关键词,对该线程进行加锁
当司机的接单程序运行时,只能是单线程,不能够多线程,当该线程释放以后才能够继续调用该程序,也就是利用synchronized关键词对司机接单的方法进行加锁
public synchronized void dispatchRealTimeOrder(OrderInfo orderInfo){
}
- 并发范围缩小
synchronized加锁方法时,对资源的消耗较大,为了节省资源,可用对某一个变量进行加锁,这样可用减少对资源的消耗。
//锁driverId 的小技巧,加intern方法
synchronized ((driverId+"").intern()){
}
并发问题Redisson解决思路
在微服务中,对一个服务进行多次部署,由于synchronized加锁是jvm级别的,在多个服务中,只能互斥,也就是只能管一个服务,不能加锁其它相同的服务,此时就会导致一个司机同时接几个不同的乘客的情况发生,多个订单匹配到了一个司机
- 分布式Redisson解决方案
在两个服务公共的部分添加锁,当一个请求拿着锁来执行代码时,其它请求就不能拿到锁来执行,利用redisson来解决
导入pom文件
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.17.7</version>
</dependency>
yml配置文件
spring:
application:
name: service-order
cloud:
discovery:
server-addr: 127.0.0.1:8848
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.3.220:12345/service-order?characterEncoding=utf8&serverTimezone=UTC
username: root
password: 123456
redis:
database: 1
host: 192.168.3.220
port: 6379
password:
timeout: 5000
在config包下创建RedisConfig的配置文件
@Component
public class RedisConfig {
private String potocol = "redis://";
@Value("${spring.redis.host}")
private String redisHost;
@Value("${spring.redis.port}")
private String redisPort;
@Bean
public RedissonClient redissonClient(){
Config config = new Config();
config.useSingleServer().setAddress(potocol+redisHost+":"+redisPort).setDatabase(0);
return Redisson.create(config);
}
}
在业务层对driverId进行上锁
//加锁
String lockKey = (driverId+"").intern();
RLock lock = redisConfig.redissonClient().getLock(lockKey);
lock.lock();
//业务逻辑
//解锁
lock.unlock();