Redisson实现
要实现只有一个骑手接到外卖配送单子,可以使用分布式锁来确保只有一个骑手能够成功接单。下面是一种基于Java和Spring Boot的实现方式:
- 引入依赖:在项目的pom.xml文件中添加以下依赖,用于使用分布式锁的功能。这是一个示例,你可以根据具体需求选择适合的分布式锁库。
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.16.2</version>
</dependency>
- 配置Redisson:在Spring Boot的配置文件中添加Redisson的配置,用于连接Redis服务。
spring:
redis:
host: your-redis-host
port: your-redis-port
- 创建接单服务:创建一个接单服务类,使用分布式锁来保证只有一个骑手能够成功接单。
package com.tan.springboot2.p1;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
@Slf4j
@Service
public class OrderService {
private static final String LOCK_KEY = "order-lock:";
@Autowired
private RedissonClient redissonClient;
public boolean takeOrder(Integer orderId) {
RLock lock = redissonClient.getLock(LOCK_KEY + orderId);
try {
// 尝试获取分布式锁,设置锁的过期时间,避免锁长时间占用
boolean locked = lock.tryLock(10, 300, TimeUnit.SECONDS);
if (locked) {
log.info("cg");
// 在这里实现接单逻辑
Thread.sleep(280 * 1000L);
// ...
return true; // 接单成功
} else {
log.info("sb");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock(); // 释放锁
}
}
return false; // 接单失败
}
}
package com.tan.springboot2.p1;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
//(160条消息) 如果一个外卖配送单子要发布,现在有200个骑手都想要接这一单,如何保证只有一个骑手接到单子?_powerTan01的博客-CSDN博客
//https://blog.csdn.net/tanwu1/article/details/130721622
@RestController
@RequestMapping("/p1")
public class P {
@Autowired
OrderService orderService;
@GetMapping("/m/{orderId}")
public boolean m(@PathVariable Integer orderId) {
return orderService.takeOrder(orderId);
}
}
在上述代码中,通过RedissonClient获取一个分布式锁实例,并使用tryLock
方法尝试获取锁。如果成功获取到锁,则执行接单逻辑,完成后释放锁。如果无法获取到锁,表示已经有其他骑手接单,返回接单失败。
这样,当有多个骑手同时调用takeOrder
方法时,只有一个骑手能够成功获取到分布式锁并接单,其他骑手将无法获取到锁,从而实现了只有一个骑手能够接到单子的效果。
请注意,在使用分布式锁时,需要确保Redis服务正常运行,并且配置的锁过期时间合理,以避免锁长时间占用。此外,还需处理可能的异常情况,例如锁获取超时或中断等。
以上是一个基于Java和Spring Boot的实现示例,具体实现方式可能会根据实际需求和项目架构有所不同。
boolean locked = lock.tryLock(10, 300, TimeUnit.SECONDS); 锁续期规则是怎么样
在Redisson中,使用tryLock
方法获取分布式锁时,可以指定一个锁续期的时间。当成功获取到锁时,会为该锁设置一个过期时间,并在到期前不断自动进行续期。
锁续期规则如下:
- 初始获取锁时,设置的过期时间即为锁的初始过期时间。
- 在获取锁成功后,Redisson会在锁的过期时间的2/3处开始自动进行续期。
- 续期的时间间隔是通过心跳机制来控制的,每隔一定的时间,Redisson会向Redis发送续期指令,更新锁的过期时间。
具体的续期机制可以保证在获取锁成功后,只要锁的持有者仍在运行,并且没有发生异常情况,锁会一直持有,直到锁的持有者释放锁或发生锁超时。
在tryLock
方法中,你可以传入等待时间参数,用于等待获取锁的最大时间。如果在等待时间内无法获取到锁,tryLock
方法会返回false
,表示获取锁失败。
需要注意的是,锁的续期是在Redisson客户端自动进行的,而不是在Redis服务器端。因此,如果Redisson客户端发生意外终止或网络故障,可能导致锁无法进行续期,最终导致锁的过期。
综上所述,通过合理设置锁的过期时间和等待时间,可以在分布式环境中实现可靠的锁续期机制。但仍需注意处理可能的异常情况和故障恢复策略,以确保锁的正常使用。
org.redisson.api.RLock#tryLock 不会锁续期 对吗,怎么锁续期
org.redisson.api.RLock#tryLock
方法是 Redisson 分布式锁中的一种尝试获取锁的方式。这个方法是非阻塞的,它会尝试获取锁,如果成功获取到锁,则返回 true
,否则返回 false
。关于锁的续期,Redisson 在锁的基础上提供了自动续期的机制。
在 Redisson 中,一旦通过 RLock
获取到锁,就会启动一个续期任务,定期地给锁进行续期,防止锁的持有者因为各种原因导致锁过期而被释放。默认情况下,锁的续期时间是30秒,如果在这个时间内锁的持有者一直在持有锁,那么锁会被自动续期,避免因为锁过期而导致其他线程获取到锁。
如果你想要手动调整续期时间,可以使用 org.redisson.api.RLock#lock(long leaseTime, TimeUnit unit)
方法,其中 leaseTime
参数表示锁的持有时间,unit
参数表示时间单位。通过这个方法可以手动设置锁的持有时间,超过指定时间后锁会自动释放。
示例代码:
RLock lock = redisson.getLock("myLock");
try {
boolean isLocked = lock.tryLock(10, TimeUnit.SECONDS); // 尝试获取锁,最多等待10秒
if (isLocked) {
// 成功获取到锁,执行业务逻辑
// ...
// 手动续期,设置锁的持有时间为60秒
lock.lock(60, TimeUnit.SECONDS);
} else {
// 未能获取到锁,处理获取失败的逻辑
// ...
}
} finally {
// 释放锁
lock.unlock();
}
在上述代码中,lock(60, TimeUnit.SECONDS)
表示手动设置锁的持有时间为60秒,即在获取锁成功后,60秒内一直持有锁,并且在这60秒内定期续期,避免因为锁过期而被释放。
代码
https://github.com/tanwu001/springboot2.1
p1包中