用Redisson的延迟队列RDelayedQueue处理延迟任务或者定时任务

什么是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秒。

 

posted @ 2024-06-05 13:44  请别耽误我写BUG  阅读(26)  评论(0编辑  收藏  举报