工具篇-- 定时任务quartz

文章目录

  • 前言
  • 一、quartz 介绍:
  • 二、quartz 的简单使用:
    • 2.1 引入jar:
    • 2.2 定义任务:
  • 三、quartz 核心组件:
    • 3.1 JobDetail:
      • 3.1.1 JobDetail介绍:
      • 3.1.2 JobDetail 和job 的关系:
    • 3.2 trigger:
      • 3.2.1 trigger 介绍:
      • 3.2.2 trigger 和jobDetail 的关系:
    • 3.3 schedule:
      • 3.3.1 schedule 介绍:
  • 四、扩展:
    • 4.1 并发执行注解:
    • 4.2 数据持久化:
    • 4.3 任务失火(misfilre) :
      • 4.3.1 SimpleScheduleBuilder 简单调度任务器失火策略:
      • 4.3.2 CronScheduleBuilder Cron 调度器失火策略:
    • 4.4 任务执行过程中抛出异常 :
      • 4.4.1 任务异常后手动触发补偿本次任务:
      • 4.4.2 任务异常后续改关联任务不在执行:
    • 4.4 日期排除 :
  • 总结:
  • 参考:


前言


在项目开发中我们经常需要在某个特定的时间做业务处理,如发生生日祝福,除夕拜年短信等,那么就需要使用定时任务框架来解决;

一、quartz 介绍:

Quartz是一个功能丰富的开源任务调度库,用于在Java应用程序中进行任务调度。它提供了一种灵活而强大的方式来定义和安排任务的执行时间,支持周期性任务、延迟任务、固定间隔任务等。

Quartz的特点和功能:

  • 灵活的任务调度:Quartz可以根据各种调度规则定义任务的执行时间,如固定延迟、固定间隔、Cron表达式等。可以轻松地创建简单或复杂的任务调度方案。

  • 分布式调度支持:Quartz支持分布式任务调度,可在多个节点上运行并协调任务的执行。这种分布式架构提供了可靠、高可用的任务调度解决方案。

  • 持久化存储:Quartz支持将任务和触发器的状态信息存储在数据库中,以便在应用程序重启后能够保持任务的持久化和恢复。它提供了与多种数据库的集成,并有内置的任务存储机制。

  • 错误恢复和重试机制:Quartz提供了丰富的错误处理和恢复机制,以确保任务执行的稳定性。如果任务执行失败,Quartz会根据预定义的策略进行错误处理和任务重试。

  • 监控和管理:Quartz提供了一套管理和监控API,可用于手动管理任务调度器、查询任务和触发器的状态、查看执行日志等。这些API可以方便地集成到的应用程序或管理工具中。

  • 插件扩展性:Quartz具有良好的扩展性,允许开发人员编写自定义的任务存储、调度器监听器、触发器监听器等插件,以满足特定的需求和业务逻辑。

二、quartz 的简单使用:

2.1 引入jar:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

2.2 定义任务:

(1)任务的执行HelloJob :

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;import java.text.SimpleDateFormat;
import java.util.Date;public class HelloJob implements Job {@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");System.out.println("\"job 执行\" = " + "job 执行" + sdf.format(new Date()));}
}

(2)任务的调度:

import com.example.springmvctest.job.quartz1.HelloJob;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.impl.StdSchedulerFactory;import static org.quartz.JobBuilder.newJob;
import static org.quartz.SimpleScheduleBuilder.simpleSchedule;
import static org.quartz.TriggerBuilder.newTrigger;public class QuartzTest {public static void main(String[] args) {try {// Grab the Scheduler instance from the FactoryScheduler scheduler = StdSchedulerFactory.getDefaultScheduler();// and start it offscheduler.start();// define the job and tie it to our HelloJob classJobDetail job = newJob(HelloJob.class).withIdentity("job1", "group1").build();// Trigger the job to run now, and then repeat every 40 secondsTrigger trigger = newTrigger().withIdentity("trigger1", "group1").startNow().withSchedule(simpleSchedule().withIntervalInSeconds(5).repeatForever()).build();// Tell quartz to schedule the job using our triggerscheduler.scheduleJob(job, trigger);Thread.sleep(20000);scheduler.shutdown();} catch (SchedulerException se) {se.printStackTrace();} catch (InterruptedException e) {throw new RuntimeException(e);}}
}

HelloJob:

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.StringJoiner;public class HelloJob implements Job {@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//        System.out.println("\"job 执行\" = " + "job 执行" + sdf.format(new Date()));StringJoiner outStr = new StringJoiner("").add("job 执行").add(sdf.format(new Date())).add(Thread.currentThread().getName()).add(jobExecutionContext.getTrigger().getKey().getName());System.out.println(outStr);}
}

在这里插入图片描述

三、quartz 核心组件:

在这里插入图片描述

调度器( Scheduler) 通过触发器(trigger) 执行任务(job):

3.1 JobDetail:

3.1.1 JobDetail介绍:

在Quartz中,JobDetail是描述任务(Job)的具体细节的类。它包含了任务的标识、执行类、执行时所需的数据/参数等信息。

以下是JobDetail的一些主要属性:

  • name:任务名称,同一个分组下必须是唯一的。
  • group:任务分组,用于将任务进行分类,方便管理和调度。
  • jobClass:任务执行类,即实现了org.quartz.Job接口的类。它负责实际执行任务任务的逻辑,真正的业务代码执行。
  • jobDataMap:任务的数据/参数,可以传递一些额外的数据给任务类,供其使用。
  • durability:任务的持久性标志,指示任务是否应该存储在调度器中,即使没有与之关联的触发器。
  • requestsRecovery:任务的失败恢复标志,指示任务是否应该在调度器发生故障后恢复执行。

使用JobDetail,可以定义要执行的具体任务的细节,并为任务提供必要的信息。例如,可以指定任务的名称、分组、执行类和参数等。当Quartz调度器触发任务时,将使用JobDetail中定义的信息来执行相应的任务逻辑。

以下是示例代码,展示如何创建一个JobDetail对象:

JobDetail jobDetail = JobBuilder.newJob(MyJob.class).withIdentity("jobName", "jobGroup").usingJobData("param1", "value1").build();

在上述示例中,创建了一个JobDetail对象,指定了任务的执行类为MyJob,名称为"jobName",分组为"jobGroup",并使用了一个名为"param1"的参数。

JobDetail是Quartz中重要的概念之一,它定义了要执行的任务的详细信息。调度器使用JobDetail来创建任务的实例,并将其与对应的触发器进行关联,以实现任务的执行调度。

3.1.2 JobDetail 和job 的关系:

在Quartz中,JobDetailJob是密切相关的,并且存在父子关系, 在设计上可以将job 包装成各种各样的 jobDetai,一个Job 可以对应为多个jobDetai,但是一个jobDetai 只能对用某一个job,但是通常在业务开发中 一个job 只创建一个jobDetai 。

JobDetail是描述任务的具体细节的类,它包含了任务的标识、执行类、执行时所需的数据/参数等信息。它是任务的静态信息。

Joborg.quartz.Job接口的实现类,负责实际执行任务任务的逻辑。它是任务的动态逻辑。

在Quartz中,通过将一个JobDetail实例与一个Trigger实例相关联,形成一个任务调度的单元。当触发器触发时,调度器会使用JobDetail中的信息创建一个Job实例,并执行该实例中的任务逻辑。

换句话说,JobDetail是任务的定义,而Job是任务的实例。一个JobDetail可以有多个关联的Job实例,每个实例执行相同的逻辑。这种设计能够使任务实例具有并发执行的能力。

JobDetail是描述任务的静态信息,而Job是实际执行任务任务的动态实例。调度器使用JobDetail定义任务的细节信息,并根据触发器的触发来创建和执行相应的Job实例。

3.2 trigger:

3.2.1 trigger 介绍:

在Quartz中,Trigger是用于定义任务(Job)执行时间的组件。它指定了任务应该何时运行、运行频率和执行规则。

Trigger可以分为以下几种类型:

  • SimpleTrigger:简单触发器,用于指定任务在特定时间点触发一次或多次的执行。可以设置触发时间、重复次数、重复间隔等参数。

  • CronTrigger:Cron触发器,基于Cron表达式定义触发时间规则。Cron表达式可以更灵活地指定任务的触发时间,如每天的特定时间执行、每周的特定日期执行等。

  • CalendarIntervalTrigger:日历间隔触发器,以特定的日历间隔来触发任务的执行。可以指定固定的时间间隔或基于日历规则定义触发时间。

  • DailyTimeIntervalTrigger:每日时间间隔触发器,基于特定的时间间隔和每天的时间窗口来触发任务的执行。

通过使用这些不同类型的Trigger,可以灵活地定义任务的触发时间和执行规则。一旦触发器被触发,Quartz调度器将会调度与之相关联的任务(通过JobDetail),并按照预定义的规则执行任务逻辑。

以下是一个示例代码,展示如何创建一个简单触发器:

Trigger trigger = TriggerBuilder.newTrigger().withIdentity("triggerName", "triggerGroup").startNow().withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(10).repeatForever()).build();

在上述示例中,创建了一个简单触发器,设置了触发器的名称为"triggerName",分组为"triggerGroup",开始时间为当前时间,每隔10秒触发一次任务执行,重复执行无限次。

Trigger是Quartz中重要的组件之一,它定义了任务的触发时间和执行规则。通过使用不同类型的触发器,可以根据需求灵活地调度和执行任务。同时,调度器会管理触发器的调度和执行,并自动触发与之关联的相应任务的执行。

3.2.2 trigger 和jobDetail 的关系:

在Quartz中,TriggerJobDetail是密切相关的并且有着父子关系。一个jobDetail 可以被多个trigger 触发;

  • JobDetail是描述任务的静态信息,包括任务的标识、执行类、执行时所需的数据/参数等信息。
  • Trigger是用于定义任务(Job)执行时间的组件,指定了任务应该何时运行、运行频率和执行规则。

一个JobDetail可以被多个Trigger关联,并且每个Trigger都会触发一个任务实例的执行。这种关联关系使得任务可以在不同的时间点、不同的规则下被调度和执行。

在Quartz调度器中,当一个Trigger被触发时,调度器会使用与之关联的JobDetail信息创建一个Job实例,并执行该实例中定义的任务逻辑。这个Job实例是任务的动态实例。一个JobDetail可以有多个关联的Trigger,每个关联的Trigger都会创建一个新的Job实例并并发执行。

JobDetail是描述任务的静态信息,而Trigger是定义任务触发时间和执行规则的组件。一个JobDetail可以被多个Trigger关联,每个关联的Trigger将创建一个新的Job实例并执行任务逻辑。通过这种关系,Quartz可以实现丰富的任务调度和执行策略。

3.3 schedule:

3.3.1 schedule 介绍:

在Quartz中,调度(schedule)将一个具体的jobDetail 和trigger 关联起来,安排和管理任务的执行时间和频率。

调度过程包括以下步骤:

  • 创建JobDetail对象,描述任务的具体细节,包括任务的标识、执行类、执行时所需的数据/参数等信息。
  • 创建Trigger对象,定义任务的触发时间和执行规则,例如简单触发器(SimpleTrigger)、Cron触发器(CronTrigger)等。
  • JobDetail对象和Trigger对象关联起来,形成任务调度的单元。
  • 将任务调度单元通过调度器(Scheduler)的scheduleJob()方法进行调度,即安排任务的执行。
  • 调度器会根据Trigger定义的触发时间规则,按照预定的时间表执行任务。当触发时间到达时,调度器会创建一个Job实例,执行任务逻辑。
  • 任务执行完毕后,调度器会根据Trigger的定义,继续安排下一次任务的执行,并持续调度任务执行。

通过Quartz的调度功能,可以灵活地安排和管理任务的执行时间,实现定时任务和定时调度的需求。可以配置多个JobDetailTrigger来实现不同的任务调度策略,并通过调度器进行统一管理和执行。

以下是一个使用Quartz进行调度的简单示例代码:

// 创建JobDetail对象
JobDetail jobDetail = JobBuilder.newJob(MyJob.class).withIdentity("myJob", "group1").build();// 创建Trigger对象
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("myTrigger", "group1").withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(10)).build();// 创建调度器对象
Scheduler scheduler = new StdSchedulerFactory().getScheduler();// 将JobDetail对象和Trigger对象关联起来
scheduler.scheduleJob(jobDetail, trigger);// 启动调度器开始调度任务
scheduler.start();

在上述示例中,使用Quartz创建了一个任务调度的简单示例。创建了一个JobDetail对象来描述任务细节,并创建一个触发器Trigger来定义任务的触发规则,每10秒执行一次。然后将JobDetail对象和Trigger对象关联起来,并通过调度器调度任务的执行。

调度是Quartz中重要的功能之一,它允许根据需求安排和管理任务的执行时间和频率。通过灵活配置和使用调度器,可以满足定时任务和任务调度的需求。

四、扩展:

4.1 并发执行注解:

@DisallowConcurrentExecution 是否允许并行执行;加上这个注解,同一个任务不能被并行执行:
场景:
定时任务每隔 3分钟,退款订单; 每次任务执行时间假如超过了3分钟;则在第二次任务触发时,则可能发生同一个订单重复退款的情况;

此时需要增加@DisallowConcurrentExecution 让其同一个job 不能并行的执行(是否同一个job 通过JobKey 判断,JobKey 包含了job name 和group )

在这里插入图片描述

4.2 数据持久化:

PersistJobDataAfterExecution 对数据持久化只针对 jobdetail 对trigger 的jobdetail 无效,改注解可以传递数据的变化;
– 示例代码

JobDetail jobDetail = JobBuilder.newJob(QuartzTest.class).usingJobData("job","jobDetail").usingJobData("name","jobDetail").usingJobData("count",0).withIdentity("job","group1").build();@PersistJobDataAfterExecution
public class MyJob implements Job {
JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();jobDataMap.put("count",jobDataMap.getInt("count")+1);
System.out.println("\"jobcount\" = " + jobDataMap.getInt("count"));
}

1、每次任务被触发,Job都会是一个新的实例默认情况下,相同的任务可以被并发执行
2、@DisallowConcurrentExecution 可以禁止相同任务的并发行为若JobKey相同,则Quartz认为是同一个任务
3.如果任务 需要修改 dataMap,并且下次被触发时 需要用到上次修改的 dataMap;可以使用 @PersistJobDataAfterExecution当使用了@PersistobDataAfterExecution,还应认真考虑是否需要使用 @PersistJobDataAfterExecution (需要考虑并发情况下无法及时获取到被修改后的数据)
在这里插入图片描述

b,c 是任务执行时修改jobDetail 的值,并发执行时,在第三次拿到的数据是b而不是c(此时就需要增加@PersistJobDataAfterExecution 注解);

4.3 任务失火(misfilre) :

misfire,中文意思是“失火”。在 quartz 中的含义是:到了任务触发时间,但是任务却没有被触发失火的原因可能是:

  • 使用了 @DisallowConcurrentExecution 注解,而且任务的执行时间 >任务间隔
  • 线程池满了,没有资源执行任务
  • 机器宕机或者人为停止,过段时间恢复运行

4.3.1 SimpleScheduleBuilder 简单调度任务器失火策略:

当任务发生多次misfire(即多次未能按时执行)时,不同的失火策略会有不同的行为:默认按照启动时间向后正常执行任务

1). withMisfireHandlingInstructionIgnoreMisfires():该策略会忽略所有的misfire,直接跳过错过的触发时间点,等待下一个正常的触发时间。不会补偿misfire的任务。

2). withMisfireHandlingInstructionFireNow():该策略会在发生misfire时立即执行任务,不考虑原定的触发时间。会补偿一次misfire的任务等待下一个正常的触发时间,。

3). withMisfireHandlingInstructionNextWithExistingCount():当发生misfire时,触发器会被重新调度到下一个执行时间点,并保留原有的重复次数。会补偿misfire的任务,继续执行原有的重复次数。
withMisfireHandlingInstructionNextWithExistingCount():当任务发生misfire时,触发器会被重新调度到下一个执行时间点,并保留原有的重复次数。这意味着即使任务错过了之前的触发时间点,它也会继续保持原有的重复次数。例如,如果任务原定要重复10次,在第5次发生misfire后,任务会重新调度到下一个时间点,并继续执行剩余的5次,不会重置为10次。

4). withMisfireHandlingInstructionNextWithRemainingCount():当任务发生misfire时,触发器会被重新调度到下一个执行时间点,并使用剩余的重复次数。会补偿misfire的任务,使用剩余的重复次数。
withMisfireHandlingInstructionNextWithRemainingCount():当任务发生misfire时,触发器会被重新调度到下一个执行时间点,并使用剩余的重复次数。这意味着任务只会继续执行剩余的重复次数,不会考虑原有的总重复次数。例如,如果任务原定要重复10次,在第5次发生misfire后,任务会重新调度到下一个时间点,并仅执行剩余的4次。

5). withMisfireHandlingInstructionNowWithExistingCount():当任务发生misfire时,立即执行任务,并保留现有的重复次数。会补偿misfire的任务,立即执行任务并继续执行原有的重复次数。
withMisfireHandlingInstructionNowWithExistingCount():当任务发生misfire时,立即执行任务,并保留原有的重复次数。这意味着任务会立即执行,但会继续按照原有的重复次数执行,不会重置为当前次数。这样可以确保任务立即得到执行,同时继续执行剩余的重复次数
withMisfireHandlingInstructionNextWithExistingCount()会等待下一个执行时间点继续执行,而withMisfireHandlingInstructionNowWithExistingCount()会立即执行任务。根据具体业务需求和任务执行情况

6). withMisfireHandlingInstructionNowWithRemainingCount():当任务发生misfire时,立即执行任务,并使用剩余的重复次数。会补偿misfire的任务,立即执行任务并使用剩余的重复次数。
withMisfireHandlingInstructionNowWithRemainingCount():当任务发生misfire时,立即执行任务,并使用剩余的重复次数。这意味着任务会立即执行,但会继续执行剩余的重复次数,而不是重置为当前次数。即使任务之前已经重复执行了几次,misfire发生后只会执行剩余的次数。
withMisfireHandlingInstructionNextWithRemainingCount()会等待下一个执行时间点继续执行,而withMisfireHandlingInstructionNowWithRemainingCount()会立即执行任务。

4.3.2 CronScheduleBuilder Cron 调度器失火策略:

在Quartz Scheduler中,CronScheduleBuilder是用于创建基于Cron表达式的触发器的构建器。CronScheduleBuilder提供了三种不同的misfire处理指令,分别是withMisfireHandlingInstructionIgnoreMisfires()withMisfireHandlingInstructionDoNothing()withMisfireHandlingInstructionFireAndProceed(),它们各自具有不同的misfire处理策略,下面详细解释这三种策略:

1). withMisfireHandlingInstructionIgnoreMisfires():当任务发生misfire时,忽略misfire,立即执行任务。这意味着即使触发器错过了触发时间点,也会立即触发执行任务,不会考虑之前未执行的时间点。任务会尽可能快地得到执行,而未执行的触发时间将被忽略。
withMisfireHandlingInstructionIgnoreMisfires()会在任务发生misfire时立即执行一次补偿任务,而不会考虑之前错过的触发时间点。换句话说,即使任务错过了触发时间点,该策略也会立即执行一次任务,无论之前的misfire次数如何。这样可以确保任务尽快地得到执行,而不会等待到下一个预定的触发时间点再执行。

使用withMisfireHandlingInstructionIgnoreMisfires()策略时,会立即触发一次任务,但不会恢复之前未执行的触发时间点。任务将继续按照正常的调度继续执行,而不会受之前的misfire影响。这样可以确保任务尽可能快地得到执行,而不会因misfire而延迟执行。

2). withMisfireHandlingInstructionDoNothing():当任务发生misfire时,不做任何处理,等待下一个触发时间点再触发执行。这意味着如果任务错过了触发时间点,会等待下一个触发时间再次触发执行。之前的misfire不会得到补偿,任务会按照正常的调度继续执行。

3). withMisfireHandlingInstructionFireAndProceed():当任务发生misfire时,立即触发执行任务,并且按照正常的调度继续执行。这意味着任务会立即执行,同时保留原来的调度计划。之后的调度会按照正常的调度继续执行,保留了之前的misfire。

withMisfireHandlingInstructionFireAndProceed()withMisfireHandlingInstructionIgnoreMisfires()都是用于处理任务misfire的策略,它们之间的区别在于处理misfire的具体方式:

1). withMisfireHandlingInstructionFireAndProceed()

  • 当任务发生misfire时,会立即触发执行任务,并且按照正常的调度继续执行。
  • 会执行一次补偿任务,并继续按正常的调度继续执行,保留之前的misfire, 不会丢失任何misfire,可以确保任务得以补偿执行,并且按照正常的调度继续执行,保持任务的连续性。

2). withMisfireHandlingInstructionIgnoreMisfires()

  • 当任务发生misfire时,会忽略misfire,立即执行任务。
  • 会执行一次补偿任务,但会忽略之前的misfire次数,任务会尽可能快地得到执行。

总的来说,withMisfireHandlingInstructionFireAndProceed()会执行一次补偿任务并继续保留原来的调度,而withMisfireHandlingInstructionIgnoreMisfires()会忽略之前的misfire次数,立即执行一次任务但不保留之前的misfire。

4.4 任务执行过程中抛出异常 :

任务执行过程中抛出异常,后续任务正常执行,不影响后续的任务调度;如果是已知的异常,可以在catch 中进行一次处理后,重新发起下一次任务的调用;

4.4.1 任务异常后手动触发补偿本次任务:

第一种方式: 重新构建任务后 通过startNow 启动任务
在这里插入图片描述
第二种方式:
每次 调用JobExecutionContext 都会产生一个新的context:使用同一个context,对job或者trigger中的JobDataMap 进行数据修改;
在这里插入图片描述

4.4.2 任务异常后续改关联任务不在执行:

获取到跟当前job 所有的触发器,进行任务的停止执行;
第一种方式:
在这里插入图片描述
第二种方式:
在这里插入图片描述

4.4 日期排除 :

定时任务的执行,需要把某些时间排除在外;
我们想一下这样的场景,某产业园有家食堂,给 办过会员卡的用户 每天早上10点发一条短信
“xxx您好,本店今日供应午餐xxx,欢迎前来就餐”
此时就需要将节假日排除在外,quartz 中提供了几种类 来处理:
在这里插入图片描述

  • CronCalendar 用来排除 给定CronExpression表示的 时间集
  • AnnualCalendar 用来排除 年 中的 天
  • HolidayCalendar 用来排除 某年 中的 某天 (与 AnnualCalendar 类似,区别是把年考虑进去了)
  • MonthlyCalendar用来排除 月 中的 天
  • WeeklyCalendar 用来排除 星期 中的 天
  • DailyCalendar 用来排除 一天中的 某个时间段 (不能跨天)(可以反转时间段的作用)

用法示例:
在这里插入图片描述


总结:

quartz 中通过定义JobDetail 来对某个业务进行包装,并定义触发器来支持该任务何时被执行,最后通过调度器将jobDetail 和trigger 进行管理,在任务触发时 调度器 通过jobDetail 实例化一个job 对象进行业务的处理;

参考:

1 quartz 快速上手(quartz官网 );

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于Spring Boot的安康旅游网站的设计与实现,计算机毕业设计(带源码+论文)

源码获取地址&#xff1a; 码呢-一个专注于技术分享的博客平台一个专注于技术分享的博客平台,大家以共同学习,乐于分享,拥抱开源的价值观进行学习交流http://www.xmbiao.cn/resource-details/1760645517548793858

【动态规划专栏】专题四:子数组问题--------最大子数组和环形子数组的最大和

本专栏内容为&#xff1a;算法学习专栏&#xff0c;分为优选算法专栏&#xff0c;贪心算法专栏&#xff0c;动态规划专栏以及递归&#xff0c;搜索与回溯算法专栏四部分。 通过本专栏的深入学习&#xff0c;你可以了解并掌握算法。 &#x1f493;博主csdn个人主页&#xff1a;小…

现货黄金中短线投资该怎么做?

要明确什么是现货黄金的中短线投资&#xff0c;中短线投资是指在短期内&#xff08;一般为几天至几周&#xff09;对现货黄金进行买卖操作&#xff0c;以期获得收益的投资方式。相较于长线投资&#xff0c;中短线投资的风险相对较大&#xff0c;但同时收益也更为可观。那么&…

【TCP/IP】内核网络堆栈

在Linux内核中&#xff0c;网络堆栈&#xff08;network stack&#xff09;是一套实现网络通信功能的软件包&#xff0c;负责处理数据包的发送和接收。网络堆栈按照OSI模型&#xff08;开放式系统互联通信参考模型&#xff09;或TCP/IP模型的层次结构来组织&#xff0c;实现了从…

数据结构2.22

思维导图顺序表(按位置插入、按位置删除和去重) //main.c #include "seq_list.h" int main() {seq_p L create_seq_list();insert_head(L,23);insert_head(L,20);insert_head(L,9);insert_head(L,20);insert_head(L,20);insert_head(L,6);insert_pos(L,321,2);inser…

2024牛客寒假算法基础集训营3 -BDGH

B题 &#xff1a;智乃的数字手串 思路&#xff1a; 思维题&#xff0c;本题题意N个数组首尾相连&#xff0c;然后当某两个相邻数组和为偶数时&#xff0c;交替拿走&#xff0c;并在选择两个数字交换位置&#xff0c;直到没有可以操作的数字为止。 我们可以考虑&#xff0c;数字…

016—pandas 分析近100年圣诞节日期分布

需求&#xff1a; 利用Pandas 分析近100年圣诞节的星期分布&#xff0c;目的是知道圣诞节都在星期几&#xff0c;哪个星期多些。 思路&#xff1a; 用 pd.date_range 生成 100 年日期数据 筛选出12月25日的所有日期 将日期转换为星期几 统计重复值的数量 绘图 二、…

LeetCode 热题 100 Day01

哈希模块 哈希结构&#xff1a; 哈希结构&#xff0c;即hash table&#xff0c;哈希表|散列表结构。 图摘自《代码随想录》 哈希表本质上表示的元素和索引的一种映射关系。 若查找某个数组中第n个元素&#xff0c;有两种方法&#xff1a; 1.从头遍历&#xff0c;复杂度&#xf…

快速鲁棒的ICP(一)

一、代码下载以、修改以及使用 链接&#xff1a;OpenGP/sparseicp: Automatically exported from code.google.com/p/sparseicp (github.com) 解压之后&#xff1a; 快速鲁棒的ICP是其他人在这份Sparse ICP代码基础上改写出来的&#xff1a; 我这里已经下载好了&#xff1a;…

代码随想录算法训练营day19||二叉树part06、654.最大二叉树 ● 617.合并二叉树 ● 700.二叉搜索树中的搜索 ● 98.验证二叉搜索树

654.最大二叉树 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点&#xff0c;其值为 nums 中的最大值。递归地在最大值 左边 的 子数组前缀上 构建左子树。递归地在最大值 右边 的 子数组后缀上 构建右子树。 返回 nums …

《VitePress 简易速速上手小册》第7章 高级功能与动态内容(2024 最新版)

文章目录 7.1 动态路由与 API 集成7.1.1 基础知识点解析7.1.2 重点案例&#xff1a;技术博客7.1.3 拓展案例 1&#xff1a;电商网站7.1.4 拓展案例 2&#xff1a;事件管理网站 7.2 状态管理与 Vuex 使用7.2.1 基础知识点解析7.2.2 重点案例&#xff1a;用户认证系统7.2.3 拓展案…

IEEE802.11k协议介绍

IEEE802.11k协议简介 协议全称&#xff1a;无线局域网的无线电资源测量(Radio Resource Measurement of Wireless LANs)批准日期&#xff1a;2008年5月协议状态&#xff1a;并入802.11-2012协议别名&#xff1a;辅助漫游协议说明&#xff1a; 定义了接入点(AP)和终端(STA&…