什么是Redisson
Redisson在基于NIO的Netty框架上,充分的利用了Redis键值数据库提供的一系列优势,在Java实用工具包中常用接口的基础上,为使用者提供了一系列具有分布式特性的常用工具类。
什么是RDelayedQueue
获取RDelayedQueue:
public <V> RDelayedQueue<V> getDelayedQueue(RQueue<V> destinationQueue) {
if (destinationQueue == null) {
throw new NullPointerException();
}
return new RedissonDelayedQueue<V>(queueTransferService, destinationQueue.getCodec(), commandExecutor, destinationQueue.getName());
}
RDelayedQueue是一种延迟队列接口,Redisson自带一个叫‘RedissonDelayedQueue’的实现类是他的子类,用于实现延迟任务。注意根据上面源码可以看到用Redisson获取RDelayedQueue时需要传一个实现RQueue队列的参数,而Redisson又可以创建另一个队列叫‘RedissonBlockingDeque’,它就是实现RBlockingDeque接口的阻塞队列,而RBlockingDeque又是RQueue的子类。
获取:RBlockingDeque:
public <V> RBlockingDeque<V> getBlockingDeque(String name) {
return new RedissonBlockingDeque<V>(commandExecutor, name, this);
}
RDelayedQueue的使用方法
1、项目中要配置Redis,然后根据Redis配置Redisson;
#Redis配置
# Redis数据库索引(默认为0)
# Redis服务器地址
# Redis服务器连接端口
# Redis服务器连接密码(默认为空)
# 链接超时时间 单位 ms(毫秒)
# 连接池最大连接数(使用负值表示没有限制) 默认 8
# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
# 连接池中的最大空闲连接 默认 8
# 连接池中的最小空闲连接 默认 0
redis:
database: 0
host: 127.0.0.1
port: 6379
connect-timeout: 3000
password:
lettuce:
pool:
max-active: 8
max-wait: -1
max-idle: 8
min-idle: 0
RedissonConfig:
@Configuration
public class RedissonConfig {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private String port;
@Value("${spring.redis.database}")
private int database;
@Bean
public RedissonClient getRedisson() {
Config config = new Config();
String address = "redis://" + host + ":" + port;
config.useSingleServer().setAddress(address).setDatabase(database);
return Redisson.create(config);
}
}
2、通过Redisson获取阻塞队列(RBlockingDeque)的子类:RedissonBlockingDeque,并通过它获取延迟队列(RDelayedQueue)的子类:RedissonDelayedQueue;
RBlockingDeque<User> blockingDeque = redissonClient.getBlockingDeque("demoName");
RDelayedQueue<User> delayedQueue = redissonClient.getDelayedQueue(blockingDeque);
delayedQueue.offer(user, 5, TimeUnit.SECONDS);
//记录设置任务的时间
System.out.println(user.getUserId() + "添加时间是:" + LocalDateTime.now());
//开启新线程执行任务,不阻塞主线程
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
User user2 = blockingDeque.poll();
if (user2 != null) {
System.out.println(user2);
System.out.println(user2.getUserId() + "执行时间是:" + LocalDateTime.now());
}
}
}
}).start();
3、让RedissonDelayedQueue的‘offer’方法添加延迟任务对象,然后通过RedissonBlockingDeque的‘poll’或者‘take’方法获取延迟任务对象然后进行后续操作。
队列take()和poll()的区别:
take():返回队列的头元素,并把它从队列中删除,如果队列为空时则阻塞线程直到有新的元素添加进来并返回;
poll():返回队列的头元素,并把它从队列中删除,如果队列头元素为空则返回null但是不阻塞线程;
使用项目Demo
任务需求:新增一个对象User,并让他5s以后介绍自己(toString方法打印信息)。
项目结构:
pom依赖:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.code</groupId>
<artifactId>MyRDelayedQueue</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!-- starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.5.4</version>
</dependency>
<!-- Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.5.4</version>
</dependency>
<!-- Redisson -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.20.0</version>
</dependency>
</dependencies>
</project>
application.yml文件:
#Redis配置
# Redis数据库索引(默认为0)
# Redis服务器地址
# Redis服务器连接端口
# Redis服务器连接密码(默认为空)
# 链接超时时间 单位 ms(毫秒)
# 连接池最大连接数(使用负值表示没有限制) 默认 8
# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
# 连接池中的最大空闲连接 默认 8
# 连接池中的最小空闲连接 默认 0
spring:
redis:
database: 0
host: 127.0.0.1
port: 6379
connect-timeout: 3000
password:
lettuce:
pool:
max-active: 8
max-wait: -1
max-idle: 8
min-idle: 0
server:
port: 8080
启动类:
@SpringBootApplication
public class MyRDQueueApplication {
public static void main(String[] args) {
SpringApplication.run(MyRDQueueApplication.class, args);
}
}
Redisson配置文件:
@Configuration
public class RedissonConfig {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private String port;
@Value("${spring.redis.database}")
private int database;
@Bean
public RedissonClient getRedisson() {
Config config = new Config();
String address = "redis://" + host + ":" + port;
config.useSingleServer().setAddress(address).setDatabase(database);
return Redisson.create(config);
}
}
User:
public class User {
private String userId;
private String userName;
private String password;
public User() {
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
//介绍自己
public String Speak() {
return "我的信息是:{" +
"userId='" + userId + '\'' +
", userName='" + userName + '\'' +
", password='" + password + '\'' +
'}';
}
}
controller:
@RestController
public class IndexController {
@Autowired
public QueueService queueService;
@RequestMapping("/queue")
public String addUser(){
return queueService.addUser();
}
}
service:
@Service
public class QueueService {
@Autowired
public RedissonClient redissonClient;
public String addUser() {
//新增User
User user = new User();
user.setUserId("123456");
user.setUserName("queueTask");
user.setPassword("666666");
//5秒后让新增的User讲话
RBlockingDeque<User> blockingDeque = redissonClient.getBlockingDeque("speak");
RDelayedQueue<User> delayedQueue = redissonClient.getDelayedQueue(blockingDeque);
delayedQueue.offer(user, 5, TimeUnit.SECONDS);
//指定日期格式
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
//打印添加任务时间
System.out.println("添加时间:" + formatter.format(LocalDateTime.now()));
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
User task = null;
try {
task = blockingDeque.take();
System.out.println(task.Speak());
//打印执行任务时间
System.out.println("执行时间:" + formatter.format(LocalDateTime.now()));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
return user.getUserId();
}
}
结果测试:
启动项目后请求路径:http://localhost:8080/queue
后台打印:
添加时间:2024-06-05 13:42:07
我的信息是:{userId='123456', userName='queueTask', password='666666'}
执行时间:2024-06-05 13:42:12
结果:执行任务时间比添加时间推迟5秒。