并发解决--上锁

177 阅读2分钟

问题背景

在一个订单匹配项目中,以网约车为例,当一个司机能够接单时,同时有多个乘客下单,此时只能有一个乘客能够匹配到该司机。

解决思路

单机解决思路

  • 利用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();