SchedulingConfigurer使用教程

news2024/10/5 15:06:34

SchedulingConfigurer使用教程:Java定时任务的高阶使用

在 Java 开发中,定时任务的管理和执行是一个常见需求。Spring 提供了多种方式来处理定时任务,其中 SchedulingConfigurer 是一个强大且灵活的接口,允许我们对定时任务进行更高级的配置和管理。本文将深入探讨如何使用 SchedulingConfigurer 实现复杂的定时任务调度。

1. 什么是 SchedulingConfigurer

SchedulingConfigurer 是 Spring Framework 提供的一个接口,用于配置任务调度。它允许我们自定义任务调度器的行为,例如配置线程池、定义任务调度规则等。

2. 配置 SchedulingConfigurer

首先,我们需要实现 SchedulingConfigurer 接口,并重写 configureTasks 方法。在这个方法中,我们可以使用 ScheduledTaskRegistrar 来注册我们的定时任务。

import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;

@Configuration
@EnableScheduling
public class CustomSchedulingConfigurer implements SchedulingConfigurer {

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        // 这里可以添加自定义的任务调度逻辑
    }
}

3. 配置线程池

为了更好地管理和优化定时任务的执行,我们通常需要配置一个线程池。通过 ScheduledTaskRegistrar,我们可以很方便地设置一个自定义的线程池。

import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;

@Configuration
@EnableScheduling
public class CustomSchedulingConfigurer implements SchedulingConfigurer {

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.setPoolSize(10);
        taskScheduler.setThreadNamePrefix("Scheduled-Task-");
        taskScheduler.initialize();
        taskRegistrar.setTaskScheduler(taskScheduler);
    }
}

在上面的代码中,我们创建了一个 ThreadPoolTaskScheduler,并设置了线程池的大小和线程名称的前缀。然后,我们将这个任务调度器注册到 ScheduledTaskRegistrar 中。

4. 注册定时任务

configureTasks 方法中,我们可以使用 ScheduledTaskRegistrar 来注册我们的定时任务。我们可以使用 Cron 表达式来定义任务的执行时间。

import org.springframework.scheduling.support.CronTrigger;

@Configuration
@EnableScheduling
public class CustomSchedulingConfigurer implements SchedulingConfigurer {

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.setPoolSize(10);
        taskScheduler.setThreadNamePrefix("Scheduled-Task-");
        taskScheduler.initialize();
        taskRegistrar.setTaskScheduler(taskScheduler);

        // 注册定时任务
        taskRegistrar.addTriggerTask(
            () -> System.out.println("定时任务执行: " + System.currentTimeMillis()),
            new CronTrigger("0/5 * * * * ?")
        );
    }
}

在上面的代码中,我们使用 addTriggerTask 方法注册了一个每 5 秒执行一次的定时任务。任务的逻辑可以是任何符合 Runnable 接口的代码。

5. 动态调整定时任务

有时候,我们需要在运行时动态调整定时任务的调度规则。我们可以通过维护一个共享变量来实现这一点。

import java.util.concurrent.atomic.AtomicReference;

@Configuration
@EnableScheduling
public class CustomSchedulingConfigurer implements SchedulingConfigurer {

    private final AtomicReference<String> cronExpression = new AtomicReference<>("0/5 * * * * ?");

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.setPoolSize(10);
        taskScheduler.setThreadNamePrefix("Scheduled-Task-");
        taskScheduler.initialize();
        taskRegistrar.setTaskScheduler(taskScheduler);

        // 注册定时任务
        taskRegistrar.addTriggerTask(
            () -> System.out.println("定时任务执行: " + System.currentTimeMillis()),
            triggerContext -> {
                String cron = cronExpression.get();
                return new CronTrigger(cron).nextExecutionTime(triggerContext);
            }
        );
    }

    // 动态修改 cron 表达式
    public void updateCronExpression(String newCron) {
        cronExpression.set(newCron);
    }
}

在上面的代码中,我们使用 AtomicReference 来保存 cron 表达式,并在 addTriggerTask 方法中动态获取最新的 cron 表达式。通过调用 updateCronExpression 方法,我们可以在运行时更新定时任务的执行规则。

6. 使用自定义的 Trigger 实现复杂的调度规则

除了使用 CronTrigger,我们还可以创建自定义的 Trigger 实现复杂的调度规则。例如,我们可以根据特定的业务逻辑动态计算下次执行时间。

import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;

import java.util.Date;

@Configuration
@EnableScheduling
public class CustomSchedulingConfigurer implements SchedulingConfigurer {

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.setPoolSize(10);
        taskScheduler.setThreadNamePrefix("Scheduled-Task-");
        taskScheduler.initialize();
        taskRegistrar.setTaskScheduler(taskScheduler);

        // 注册定时任务
        taskRegistrar.addTriggerTask(
            () -> System.out.println("定时任务执行: " + System.currentTimeMillis()),
            new CustomTrigger()
        );
    }

    private static class CustomTrigger implements Trigger {
        @Override
        public Date nextExecutionTime(TriggerContext triggerContext) {
            // 自定义计算下一次执行时间的逻辑
            return new Date(System.currentTimeMillis() + 5000);
        }
    }
}

在上面的代码中,CustomTrigger 实现了 Trigger 接口,并在 nextExecutionTime 方法中自定义了下一次执行时间的计算逻辑。

7. 多任务调度和任务优先级

如果你的应用程序中有多个定时任务,并且这些任务有不同的优先级或需要不同的调度器,我们可以为每个任务配置不同的 TaskScheduler

@Configuration
@EnableScheduling
public class MultiTaskSchedulingConfigurer implements SchedulingConfigurer {

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        // 配置任务1的调度器
        ThreadPoolTaskScheduler taskScheduler1 = new ThreadPoolTaskScheduler();
        taskScheduler1.setPoolSize(5);
        taskScheduler1.setThreadNamePrefix("Task1-");
        taskScheduler1.initialize();
        taskRegistrar.setTaskScheduler(taskScheduler1);
        taskRegistrar.addTriggerTask(
            () -> System.out.println("任务1执行: " + System.currentTimeMillis()),
            new CronTrigger("0/10 * * * * ?")
        );

        // 配置任务2的调度器
        ThreadPoolTaskScheduler taskScheduler2 = new ThreadPoolTaskScheduler();
        taskScheduler2.setPoolSize(3);
        taskScheduler2.setThreadNamePrefix("Task2-");
        taskScheduler2.initialize();
        taskRegistrar.addTriggerTask(
            () -> System.out.println("任务2执行: " + System.currentTimeMillis()),
            new CronTrigger("0/15 * * * * ?")
        );
    }
}

在上面的代码中,我们为两个任务配置了不同的 TaskScheduler,并且设置了不同的线程池和调度规则。

8. 动态添加和移除任务

在实际应用中,我们可能需要动态地添加和移除任务。我们可以通过维护一个任务列表来实现这一功能。

import java.util.ArrayList;
import java.util.List;

@Configuration
@EnableScheduling
public class DynamicGroupedTaskSchedulingConfigurer implements SchedulingConfigurer {

    private final Map<TaskGroup, ThreadPoolTaskScheduler> taskSchedulers = new HashMap<>();
    private final Map<TaskGroup, List<ScheduledFuture<?>>> scheduledTasks = new HashMap<>();

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        configureTaskScheduler(TaskGroup.GROUP_A, 5, "GroupA-Task-");
        configureTaskScheduler(TaskGroup.GROUP_B, 3, "GroupB-Task-");
    }

    private void configureTaskScheduler(TaskGroup group, int poolSize, String threadNamePrefix) {
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.setPoolSize(poolSize);
        taskScheduler.setThreadNamePrefix(threadNamePrefix);
        taskScheduler.initialize();
        taskSchedulers.put(group, taskScheduler);
        scheduledTasks.put(group, new ArrayList<>());
    }

    public void addTask(TaskGroup group, Runnable task, String cronExpression) {
        ThreadPoolTaskScheduler scheduler = taskSchedulers.get(group);
        if (scheduler != null) {
            ScheduledFuture<?> future = scheduler.schedule(task, new CronTrigger(cronExpression));
            scheduledTasks.get(group).add(future);
        }
    }

    public void removeAllTasks(TaskGroup group) {
        List<ScheduledFuture<?>> tasks = scheduledTasks.get(group);
        if (tasks != null) {
            for (ScheduledFuture<?> task : tasks) {
                task.cancel(true);
            }
            tasks.clear();
        }


    }
}

在上面的代码中,我们维护了一个任务列表 scheduledTasks,并提供了 addTaskremoveAllTasks 方法来动态地添加和移除任务。

示例使用

我们可以通过控制器或服务类来管理任务的添加和移除。

import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/tasks")
public class TaskController {

    private final DynamicGroupedTaskSchedulingConfigurer taskConfigurer;

    public TaskController(DynamicGroupedTaskSchedulingConfigurer taskConfigurer) {
        this.taskConfigurer = taskConfigurer;
    }

    @PostMapping("/add")
    public String addTask(@RequestParam TaskGroup group, @RequestParam String cron) {
        taskConfigurer.addTask(group, () -> System.out.println("动态任务执行: " + System.currentTimeMillis()), cron);
        return "任务已添加";
    }

    @DeleteMapping("/removeAll")
    public String removeAllTasks(@RequestParam TaskGroup group) {
        taskConfigurer.removeAllTasks(group);
        return "所有任务已移除";
    }
}

通过上述控制器,我们可以动态地添加和移除任务组中的任务。例如,通过以下请求可以添加和移除任务:

  • 添加任务:POST /tasks/add?group=GROUP_A&cron=0/5 * * * * ?
  • 移除任务:DELETE /tasks/removeAll?group=GROUP_A

9. 错误处理和重试机制

在某些情况下,定时任务可能会失败。为了提高任务的可靠性,我们可以为定时任务添加错误处理和重试机制。

import org.springframework.scheduling.TriggerContext;

@Configuration
@EnableScheduling
public class ErrorHandlingSchedulingConfigurer implements SchedulingConfigurer {

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.setPoolSize(10);
        taskScheduler.setThreadNamePrefix("ErrorHandling-Task-");
        taskScheduler.initialize();
        taskRegistrar.setTaskScheduler(taskScheduler);

        // 注册带错误处理和重试机制的定时任务
        taskRegistrar.addTriggerTask(
            () -> {
                try {
                    System.out.println("任务执行: " + System.currentTimeMillis());
                    // 模拟任务执行逻辑
                    if (Math.random() > 0.7) {
                        throw new RuntimeException("模拟任务执行失败");
                    }
                } catch (Exception e) {
                    System.err.println("任务执行失败: " + e.getMessage());
                    // 添加重试逻辑,例如延迟重试
                    taskScheduler.schedule(this::retryTask, new CronTrigger("0/10 * * * * ?"));
                }
            },
            new CronTrigger("0/5 * * * * ?")
        );
    }

    private void retryTask() {
        System.out.println("重试任务执行: " + System.currentTimeMillis());
    }
}

在上面的代码中,我们在任务执行逻辑中添加了错误处理逻辑,并在任务失败时使用 taskScheduler 调度重试任务。

10. 任务分组

任务分组可以帮助我们更好地组织和管理定时任务。我们可以为不同的任务分组设置不同的调度器和调度规则,从而实现更加灵活的任务管理。

10.1 定义任务组

我们可以通过一个枚举类来定义任务组,并在配置类中使用这些任务组来组织任务。

public enum TaskGroup {
    GROUP_A,
    GROUP_B
}

10.2 配置任务组调度器

为每个任务组配置不同的 TaskScheduler 和调度规则。

@Configuration
@EnableScheduling
public class GroupedTaskSchedulingConfigurer implements SchedulingConfigurer {

    private final Map<TaskGroup, ThreadPoolTaskScheduler> taskSchedulers = new HashMap<>();

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        configureTaskScheduler(TaskGroup.GROUP_A, 5, "GroupA-Task-");
        configureTaskScheduler(TaskGroup.GROUP_B, 3, "GroupB-Task-");

        // 注册任务组A的定时任务
        taskRegistrar.setTaskScheduler(taskSchedulers.get(TaskGroup.GROUP_A));
        taskRegistrar.addTriggerTask(
            () -> System.out.println("任务组A-任务1执行: " + System.currentTimeMillis()),
            new CronTrigger("0/10 * * * * ?")
        );

        // 注册任务组B的定时任务
        taskRegistrar.setTaskScheduler(taskSchedulers.get(TaskGroup.GROUP_B));
        taskRegistrar.addTriggerTask(
            () -> System.out.println("任务组B-任务1执行: " + System.currentTimeMillis()),
            new CronTrigger("0/15 * * * * ?")
        );
    }

    private void configureTaskScheduler(TaskGroup group, int poolSize, String threadNamePrefix) {
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.setPoolSize(poolSize);
        taskScheduler.setThreadNamePrefix(threadNamePrefix);
        taskScheduler.initialize();
        taskSchedulers.put(group, taskScheduler);
    }
}

在上面的代码中,我们为每个任务组配置了不同的 TaskScheduler,并在 configureTasks 方法中注册了不同的定时任务。

10.3 动态添加和移除任务

在实际应用中,我们可能需要动态地添加和移除任务。我们可以通过维护一个任务列表来实现这一功能。

import java.util.ArrayList;
import java.util.List;

@Configuration
@EnableScheduling
public class DynamicGroupedTaskSchedulingConfigurer implements SchedulingConfigurer {

    private final Map<TaskGroup, ThreadPoolTaskScheduler> taskSchedulers = new HashMap<>();
    private final Map<TaskGroup, List<ScheduledFuture<?>>> scheduledTasks = new HashMap<>();

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        configureTaskScheduler(TaskGroup.GROUP_A, 5, "GroupA-Task-");
        configureTaskScheduler(TaskGroup.GROUP_B, 3, "GroupB-Task-");
    }

    private void configureTaskScheduler(TaskGroup group, int poolSize, String threadNamePrefix) {
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.setPoolSize(poolSize);
        taskScheduler.setThreadNamePrefix(threadNamePrefix);
        taskScheduler.initialize();
        taskSchedulers.put(group, taskScheduler);
        scheduledTasks.put(group, new ArrayList<>());
    }

    public void addTask(TaskGroup group, Runnable task, String cronExpression) {
        ThreadPoolTaskScheduler scheduler = taskSchedulers.get(group);
        if (scheduler != null) {
            ScheduledFuture<?> future = scheduler.schedule(task, new CronTrigger(cronExpression));
            scheduledTasks.get(group).add(future);
        }
    }

    public void removeAllTasks(TaskGroup group) {
        List<ScheduledFuture<?>> tasks = scheduledTasks.get(group);
        if (tasks != null) {
            for (ScheduledFuture<?> task : tasks) {
                task.cancel(true);
            }
            tasks.clear();
        }
    }
}

在上面的代码中,我们维护了一个任务列表 scheduledTasks,并提供了 addTaskremoveAllTasks 方法来动态地添加和移除任务。

示例使用

我们可以通过控制器或服务类来管理任务的添加和移除。

import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/tasks")
public class TaskController {

    private final DynamicGroupedTaskSchedulingConfigurer taskConfigurer;

    public TaskController(DynamicGroupedTaskSchedulingConfigurer taskConfigurer) {
        this.taskConfigurer = taskConfigurer;
    }

    @PostMapping("/add")
    public String addTask(@RequestParam TaskGroup group, @RequestParam String cron) {
        taskConfigurer.addTask(group, () -> System.out.println("动态任务执行: " + System.currentTimeMillis()), cron);
        return "任务已添加";
    }

    @DeleteMapping("/removeAll")
    public String removeAllTasks(@RequestParam TaskGroup group) {
        taskConfigurer.removeAllTasks(group);
        return "所有任务已移除";
    }
}

通过上述控制器,我们可以动态地添加和移除任务组中的任务。例如,通过以下请求可以添加和移除任务:

  • 添加任务:POST /tasks/add?group=GROUP_A&cron=0/5 * * * * ?
  • 移除任务:DELETE /tasks/removeAll?group=GROUP_A

最佳实践

  1. 使用线程池优化性能:使用线程池可以避免线程资源耗尽,提升任务调度的性能和稳定性。
  2. 定期检查和调整任务调度:根据业务需求和系统性能,定期检查和调整定时任务的调度策略。
  3. 日志记录和监控:为定时任务添加日志记录和监控,方便排查问题和优化性能。
  4. 异常处理和重试机制:为关键任务添加异常处理和重试机制,确保任务的可靠执行。
  5. 分组管理任务:将相关任务进行分组管理,提高任务调度的灵活性和可维护性。

注意事项

  1. 避免任务堆积:确保任务执行时间短于调度周期,避免任务堆积导致系统性能下降。
  2. 合理设置线程池大小:根据实际业务需求和服务器性能,合理设置线程池的大小,避免线程资源耗尽或浪费。
  3. 避免重复调度:确保同一任务不会被重复调度,避免任务逻辑被多次执行。
  4. 监控系统资源:定时任务可能会消耗大量系统资源,需监控系统资源使用情况,防止资源耗尽。
  5. 优雅停机:在应用停机时,确保正在执行的任务能优雅终止或完成,避免数据不一致或任务中断。

通过遵循这些最佳实践和注意事项,你可以更加高效地管理和优化定时任务,确保系统的稳定性和可靠性。

结论

通过以上高级技巧,我们可以更加灵活和高效地管理定时任务。无论是自定义调度规则、多任务调度、动态启停任务,还是错误处理和重试机制,SchedulingConfigurer 都提供了丰富的扩展点。希望这些高级使用场景能够帮助你在实际项目中更好地应用定时任务调度。
如果你有其他高级使用技巧或遇到任何问题,欢迎在评论区分享和讨论。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1901351.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【vue组件库搭建04】使用vitepress搭建站点并部署到github

前言 基于vitePress搭建文档站点&#xff0c;使用github pages进行部署 安装VitePress 1.Node.js 18 及以上版本 2.npm add -D vitepress 3.npx vitepress init 4.将需要回答几个简单的问题&#xff1a; ┌ Welcome to VitePress! │ ◇ Where should VitePress initi…

ROS 2官方文档(基于humble版本)学习笔记(四)

ROS 2官方文档&#xff08;基于humble版本&#xff09;学习笔记&#xff08;四&#xff09; 2.客户端库使用colcon构建包&#xff08;package&#xff09;创建工作空间&#xff08;workspace&#xff09;构建工作空间执行测试&#xff08;tests&#xff09;导入环境&#xff08…

Java项目:基于SSM框架实现的会员积分管理系统分前后台【ssm+B/S架构+源码+数据库+毕业论文】

一、项目简介 本项目是一套基于SSM框架实现的会员积分管理系统 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作简单、功能…

springcloud-alibba之FeignClient

代码地址&#xff1a;springcloud系列: springcloud 组件分析拆解 1.FeignClient的集成 springboot版本&#xff1a;3.1.5 springcloud组件版本&#xff1a;2022.0.4 nacos客户端的版本&#xff1a;2.3.2 1.引pom 这里引入了nacos和feginclient的版本 <dependency>…

moonlight+sunshine+ParsecVDisplay ipad8-windows 局域网串流

1.sunshine PC 安装 2.设置任意账户密码登录 3.setting 里 network启用UPNP IPV4IPV6 save apply 4.ParsecVDisplay虚拟显示器安装 5.ipad appstore download moonlight 6.以ipad 8 为例 2160*1620屏幕分辨率 7.ParsecVDisplay里面 custom设置2160*1620 240hz&#xff0c;…

org.springframework.jdbc.BadSqlGrammarException异常

Bug 记录 概述 在执行定时任务更新电子书统计信息时&#xff0c;遇到了 org.springframework.jdbc.BadSqlGrammarException 异常&#xff0c;具体表现为 SQL 函数 count 被错误地解析为自定义函数 wiki.count&#xff0c;导致数据库更新操作失败。 详细描述 错误信息&#x…

本地部署到服务器上的资源路径问题

本地部署到服务器上的资源路径问题 服务器端的源代码的静态资源目录层级 当使用Thymeleaf时&#xff0c;在templates的目录下为返回的html页面&#xff0c;下面以两个例子解释当将代码部署到tomcat时访问资源的路径配置问题 例子一 index.html&#xff08;在templates的根目录…

【算法专题】双指针算法

1. 移动零 题目分析 对于这类数组分块的问题&#xff0c;我们应该首先想到用双指针的思路来进行处理&#xff0c;因为数组可以通过下标进行访问&#xff0c;所以说我们不用真的定义指针&#xff0c;用下标即可。比如本题就要求将数组划分为零区域和非零区域&#xff0c;我们不…

JavaScript-websocket的基本使用

JavaScript-websocket的基本使用 文章说明JavaScript端后台--服务端连接演示 文章说明 本文主要介绍JavaScript中websocket的基本使用&#xff0c;后台采用Java编写WebSocket服务端 JavaScript端 websocket工具类 class Socket {constructor(url, onopen, onmessage, onerror, …

【C++:类的基础认识和this指针】

C的类与C语言的struct结构体有啥区别&#xff1f; 默认的访问限定符不同 类的简要 关键字&#xff1a;class{}里面是类的主体&#xff0c;特别注意&#xff1a;{}后面的&#xff1b;不可以省略类中的变量叫做成员变量&#xff0c;类中的函数叫做成员函数类中访问有三种访问权限…

第十四届蓝桥杯省赛C++B组G题【子串简写】题解(AC)

题目大意 给定字符串 s s s&#xff0c;字符 a , b a, b a,b&#xff0c;问字符串 s s s 中有多少个 a a a 开头 b b b 结尾的子串。 解题思路 20pts 使用二重循环枚举左端点和右端点&#xff0c;判断是否为 a a a 开头 b b b 结尾的字符串&#xff0c;是则答案加一…

代码随想录——划分字母区间(Leetcode763)

题目链接 贪心 class Solution {public List<Integer> partitionLabels(String s) {int[] count new int[27];Arrays.fill(count,0);// 统计元素最后一次出现的位置for(int i 0; i < s.length(); i){count[s.charAt(i) - a] i;}List<Integer> res new Ar…

rk3588 Android HDMI IN热插拔解决

一、前言 1、公司在使用 别的厂商的板卡遇到一个问题&#xff0c;开机我们的app自启就会闪退&#xff0c;后来定位发现是camera 的open出错了&#xff0c;这个问题的出现是因为没有插HDMI IN输入的问题导致的,所以需要对HDMI IN的热插拔进行检测&#xff0c;后面我把这个问题也…

【文献解析】一种像素级的激光雷达相机配准方法

大家好呀&#xff0c;我是一个SLAM方向的在读博士&#xff0c;深知SLAM学习过程一路走来的坎坷&#xff0c;也十分感谢各位大佬的优质文章和源码。随着知识的越来越多&#xff0c;越来越细&#xff0c;我准备整理一个自己的激光SLAM学习笔记专栏&#xff0c;从0带大家快速上手激…

leetcode-每日一题

3101. 交替子数组计数https://leetcode.cn/problems/count-alternating-subarrays/ 给你一个 二进制数组 nums 。 如果一个 子数组 中 不存在 两个 相邻 元素的值 相同 的情况&#xff0c;我们称这样的子数组为 交替子数组 。 返回数组 nums 中交替子数组的数量。 示例 …

Linux|信号

Linux|信号 信号的概念信号处理的三种方式捕捉信号的System Call -- signal 1.产生信号的5种方式2.信号的保存2.1 core 标志位 2.信号的保存2.1 对pending 表 和 block 表操作2.2 阻塞SIGINT信号 并打印pending表例子 捕捉信号sigaction 函数验证当前正在处理某信号&#xff0c…

win11自动删除文件的问题,安全中心提示

win11自动删除文件的问题&#xff0c;解决方法&#xff1a; 1.点击任务栏上的开始图标&#xff0c;在显示的应用中&#xff0c;点击打开设置。 或者点击电脑右下角的开始也可以 2.点击设置。也可以按Wini打开设置窗口。 3.左侧点击隐私和安全性&#xff0c;右侧点击Windows安全…

学习笔记——动态路由——IS-IS中间系统到中间系统(区域划分)

三、IS-IS区域划分 根据IS-IS路由器邻居关系&#xff0c;可以将IS-IS划分为两个区域——骨干区域和非骨干区域。&#xff08;注意&#xff0c;这里的区域不是上文中提到的Area ID&#xff09;由L2的IS-IS邻居构成的区域为骨干区域&#xff0c;由L1的IS-IS邻居构成的区域为非骨…

动态路由--RIP配置(思科cisco)

一、简介 RIP协议&#xff08;Routing Information Protocol&#xff0c;路由信息协议&#xff09;是一种基于距离矢量的动态路由选择协议。 在RIP协议中&#xff0c;如果路由器A和网络B直接相连&#xff0c;那么路由器A到网络B的距离被定义为1跳。若从路由器A出发到达网络B需要…

在原有的iconfont.css文件中加入新的字体图标

前言&#xff1a;在阿里图标库中&#xff0c;如果你没有这个字体图标的线上项目&#xff0c;那么你怎么在本地项目中的原始图标文件中添加新的图标呢&#xff1f; 背景&#xff1a;现有一个vue项目&#xff0c;下面是这个前端项目的字体图标文件。现在需要新开发功能页&#x…