Java 之使用消息队列实现一系列的功能

为了梳理任务的流转过程,我们可以从以下几个关键点进行分析:

  1. 任务提交:任务通过BatchController中的接口方法(如laneinfopatch)被提交。
  2. 任务排队:提交的任务会被放入TaskQueue中。
  3. 任务处理TaskProcessor中的线程会从TaskQueue中取出任务并执行。
  4. 任务执行:任务执行的具体逻辑在Task类的run方法中定义。

流程图#

+-----------------+        +-----------------+        +-----------------+        +-----------------+
| BatchController |        |     TaskQueue   |        |   TaskProcessor |        |       Task      |
+-----------------+        +-----------------+        +-----------------+        +-----------------+
         |                          |                          |                          |
         | 1. 提交任务              |                          |                          |
         |------------------------->|                          |                          |
         |                          | 2. 任务入队              |                          |
         |                          |------------------------->|                          |
         |                          |                          | 3. 处理任务              |
         |                          |                          |<-------------------------|
         |                          |                          |                          |
         |                          |                          | 4. 执行任务              |
         |                          |                          |------------------------->|
         |                          |                          |                          |
         |                          |                          | 5. 任务完成              |
         |                          |                          |<-------------------------|
         |                          |                          |                          |
         |                          |                          | 6. 返回结果              |
         |                          |                          |------------------------->|
         |                          |                          |                          |
         |                          |                          | 7. 任务队列为空          |
         |                          |                          |<-------------------------|
         |                          |                          |                          |

核心逻辑#

  1. 任务提交

    • BatchController中的laneinfopatch方法接收请求参数,创建Task对象,并将其放入TaskQueue中。
    • Task对象包含执行任务所需的CallableCompletableFuture
  2. 任务排队

    • TaskQueue使用BlockingQueue来存储任务,确保任务的顺序性和线程安全。
  3. 任务处理

    • TaskProcessor启动多个线程,每个线程从TaskQueue中取出任务并执行。
    • 如果线程被中断,会重新设置中断状态并记录日志。
  4. 任务执行

    • Taskrun方法中,通过Callable执行具体的业务逻辑,并将结果放入CompletableFuture中。
    • 如果执行过程中发生异常,会记录日志并抛出RuntimeException

代码实现#

以下是核心逻辑的代码实现,主要集中在BatchControllerTaskQueueTaskProcessorTask类中。

BatchController.java#

   CompletableFuture<EntityResponse<?>> future = new CompletableFuture<>();
        Task task = Task.builder()
                .callable(() -> server.execute(param))
                .future(future)
                .build();

        try {
            taskQueue.enqueue(task); // 将任务添加到队列中
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return future.join();

TaskQueue.java#

@Component
public class TaskQueue {

    private final BlockingQueue<Task> queue = new LinkedBlockingQueue<>();

    public void enqueue(Task task) throws InterruptedException {

        queue.put(task);
    }

    public Task dequeue() throws InterruptedException {

        return queue.take();
    }

    public int size() {

        return queue.size();
    }

    public void clear() {

        queue.clear();
    }

    public boolean isEmpty() {

        return queue.isEmpty();
    }

}

TaskProcessor.java#

@Slf4j
@Service

public class TaskProcessor {

    @Resource
    private TaskQueue taskQueue;

    @Resource(name = "commonThreadPool")
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    public void processTasks() {
        // 1. 每个线程的线程任务死循环
        // 2, 这里触发的是提交任务到线程池中执行
        //3. 控制一下,提交多少个任务到线程池中
        int consumerThreadCount = 10;

        for (int i = 0; i < consumerThreadCount; i++) {
            threadPoolTaskExecutor.execute(() -> {
                while (!Thread.currentThread().isInterrupted()) {
                    try {
                        Task  task = taskQueue.dequeue();
                        task.run();
                    } catch (InterruptedException e) {
                        log.error("Thread interrupted", e);
                        Thread.currentThread().interrupt(); // 重新设置中断状态
                    } catch (Exception e) {
                        log.error("Error processing task", e);
                    }
                }
            });
        }


    }

}

Task.java#

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Task {

    private AuthInfo authInfo;

    private Callable<EntityResponse<?>> callable;

    private CompletableFuture<EntityResponse<?>> future;


    public void run() {

        try {
            AuthInfoUtils.fillVirtualAuth();
            EntityResponse<?> response = callable.call();
            future.complete(response);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            AuthInfoUtils.clear();
        }

    }

}

TaskProcessorRunner.java#

@Component
public class TaskProcessorRunner implements CommandLineRunner {

    @Resource
    private TaskProcessor taskProcessor;

    @Override
    public void run(String... args) throws Exception {

        taskProcessor.processTasks(); // 启动任务处理器


    }

}

以上代码展示了任务提交、排队、处理和执行的核心逻辑。通过这些步骤,任务能够被有序地处理,并且在处理过程中能够优雅地响应中断信号。

作者:快乐小王子

出处:https://www.cnblogs.com/alex-oos/p/18743162

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   快乐小王子帅气哥哥  阅读(1)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu