精华内容
下载资源
问答
  • Quartz定时机制 首先导入jar包到程序内 quartz-all-1.6.0.jar 然后创建个XML TimeConfig.xml 名字可以自己定义 <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.or

    Quartz定时机制
    首先导入jar包到程序内 quartz-all-1.6.0.jar
    然后创建一个XML
    TimeConfig.xml 名字可以自己定义

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
    "http://www.springframework.org/dtd/spring-beans.dtd">
    <beans>
        <bean id="mainTask" class="net.timed.MainTask"/>   //你要执行的任务类 
       //jar类
        <bean id="mainJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
            <property name="targetObject">
                           <ref bean="mainTask"/>//将你的类添加到定时器当中
             </property>
            <property name="targetMethod">
                <value>execute</value> //定时执行类里面的哪个方法
            </property>
    </bean>
    <bean id="timeTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
           <property name="jobDetail">
               <ref bean="mainJob"/>
            </property>
    <!-- 
    0 0 10,14,16 * * ? 每天上午10点,下午2点,4点
    0 0/30 9-17 * * ?   朝九晚五工作时间内每半小时
    0 0 12 ? * WED 表示每个星期三中午12点 
    "0 0 12 * * ?" 每天中午12点触发 
    "0 15 10 ? * *" 每天上午10:15触发 
    "0 15 10 * * ?" 每天上午10:15触发 
    "0 15 10 * * ? *" 每天上午10:15触发 
    "0 15 10 * * ? 2005" 2005年的每天上午10:15触发 
    "0 * 14 * * ?" 在每天下午2点到下午2:59期间的每1分钟触发 
    "0 0/5 14 * * ?" 在每天下午2点到下午2:55期间的每5分钟触发 
    "0 0/5 14,18 * * ?" 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发 
    "0 0-5 14 * * ?" 在每天下午2点到下午2:05期间的每1分钟触发 
    "0 10,44 14 ? 3 WED" 每年三月的星期三的下午2:10和2:44触发 
    "0 15 10 ? * MON-FRI" 周一至周五的上午10:15触发 
    "0 15 10 15 * ?" 每月15日上午10:15触发 
    "0 15 10 L * ?" 每月最后一日的上午10:15触发 
    "0 15 10 ? * 6L" 每月的最后一个星期五上午10:15触发 
    "0 15 10 ? * 6L 2002-2005" 2002年至2005年的每月的最后一个星期五上午10:15触发 
    "0 15 10 ? * 6#3" 每月的第三个星期五上午10:15触发 
    上面这个是quartz的语法 定时单位
     -->
            <property name="cronExpression">
                <value>0 0/5 * * * ?</value>  //定时的语法
            </property>
    </bean>
    <bean id="sfb" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
            <property name="triggers">
                <list>
                    <ref local="timeTrigger"/>
                </list>
            </property>
    </bean>
    </beans> 

    //下面这个类就是我在XML中引入的类

    package net.timed;
    import java.io.IOException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    public class MainTask {
        public void execute() throws IOException
        {
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            System.out.println("do my job"+dateFormat.format(new Date()));
            Runtime.getRuntime().exec("cmd /c start E:/mbl/BusinessOffice/MoneDB/bin/bakup.bat");
        }
    }

    然后在web.xml中把这个TimeConfig.xml添加进去作为监听
    系统启动的时候自动就监听这个事件

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="2.5" 
        xmlns="http://java.sun.com/xml/ns/javaee" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
        http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
        <context-param>
        <param-name>
            contextConfigLocation
        </param-name>
        <param-value>
            /WEB-INF/TimerConfig.xml
        </param-value>
        </context-param>
        <listener>
            <listener-class>
                org.springframework.web.context.ContextLoaderListener
            </listener-class>
        </listener>
      <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
      </welcome-file-list>
    </web-app>

    这个是quartz spring的定时机制 请仔细的看看 如果可以请给分哦

    展开全文
  • 现在工作几年后发现,很多以前过、用过的东西,再次拿起的时候总觉得记不牢靠。"好记性不如烂笔头"应该是某位上了年纪的大叔的切肤之痛(仅次于上了年纪的难言之瘾)。 我觉得这事得怪怪中国

    尊重知识产权,原文地址:http://www.cnblogs.com/drift-ice/p/3817269.html

    Quartz使用总结

    废话的前言

    以前凭借年轻,凡事都靠脑记。现在工作几年后发现,很多以前看过、用过的东西,再次拿起的时候总觉得记不牢靠。"好记性不如烂笔头"应该是某位上了年纪的大叔的切肤之痛(仅次于上了年纪的难言之瘾)。

    我觉得这事得怪怪中国的应试教育,中国的考试方式就是要求把脑袋当数据库,以前中学那点知识,确实还能装得下。但现在所需的知识量再一次性装入大脑,就是内存溢出的节奏。另,再相信什么人脑只开发5%的蠢话了(「人脑只用了不到 5%」 的说法是否确有科学依据?)。更可行的方式,应该学学数据库,大脑只记忆知识的索引,而把知识的本身定义在外部的存储中(比如笔记)。基于这个理念,现在准备学着写点总结性的笔记。

    那为什么不能基于google学习呢?因为google的索引不是你自己,不能精确找到你想要的东西。但它的好处是更海量,能给你原本压根不知道东西。所以,配合使用,疗效更好。

    Quartz可以用来做什么?

    Quartz是一个任务调度框架。比如你遇到这样的问题

    • 想每月25号,信用卡自动还款
    • 想每年4月1日自己给当年暗恋女神发一封匿名贺卡
    • 想每隔1小时,备份一下自己的爱情动作片 学习笔记到云盘

    这些问题总结起来就是:在某一个有规律的时间点干某件事。并且时间的触发的条件可以非常复杂(比如每月最后一个工作日的17:50),复杂到需要一个专门的框架来干这个事。 Quartz就是来干这样的事,你给它一个触发条件的定义,它负责到了时间点,触发相应的Job起来干活。

    一个简单的示例

    这里面的所有例子都是基于Quartz 2.2.1

    package com.test.quartz;
    
    import static org.quartz.DateBuilder.newDate;
    import static org.quartz.JobBuilder.newJob;
    import static org.quartz.SimpleScheduleBuilder.simpleSchedule;
    import static org.quartz.TriggerBuilder.newTrigger;
    
    import java.util.GregorianCalendar;
    
    import org.quartz.JobDetail;
    import org.quartz.Scheduler;
    import org.quartz.Trigger;
    import org.quartz.impl.StdSchedulerFactory;
    import org.quartz.impl.calendar.AnnualCalendar;
    
    public class QuartzTest {
    
        public static void main(String[] args) {
            try {
                //创建scheduler
                Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
    
                //定义一个Trigger
                Trigger trigger = newTrigger().withIdentity("trigger1", "group1") //定义name/group
                    .startNow()//一旦加入scheduler,立即生效
                    .withSchedule(simpleSchedule() //使用SimpleTrigger
                        .withIntervalInSeconds(1) //每隔一秒执行一次
                        .repeatForever()) //一直执行,奔腾到老不停歇
                    .build();
    
                //定义一个JobDetail
                JobDetail job = newJob(HelloQuartz.class) //定义Job类为HelloQuartz类,这是真正的执行逻辑所在
                    .withIdentity("job1", "group1") //定义name/group
                    .usingJobData("name", "quartz") //定义属性
                    .build();
    
                //加入这个调度
                scheduler.scheduleJob(job, trigger);
    
                //启动之
                scheduler.start();
    
                //运行一段时间后关闭
                Thread.sleep(10000);
                scheduler.shutdown(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    package com.test.quartz;
    
    import java.util.Date;
    
    import org.quartz.DisallowConcurrentExecution;
    import org.quartz.Job;
    import org.quartz.JobDetail;
    import org.quartz.JobExecutionContext;
    import org.quartz.JobExecutionException;
    
    public class HelloQuartz implements Job {
        public void execute(JobExecutionContext context) throws JobExecutionException {
            JobDetail detail = context.getJobDetail();
            String name = detail.getJobDataMap().getString("name");
            System.out.println("say hello to " + name + " at " + new Date());
        }
    }
    

    这个例子很好的覆盖了Quartz最重要的3个基本要素:

    • Scheduler:调度器。所有的调度都是由它控制。
    • Trigger: 定义触发的条件。例子中,它的类型是SimpleTrigger,每隔1秒中执行一次(什么是SimpleTrigger下面会有详述)。
    • JobDetail & Job: JobDetail 定义的是任务数据,而真正的执行逻辑是在Job中,例子中是HelloQuartz。 为什么设计成JobDetail + Job,不直接使用Job?这是因为任务是有可能并发执行,如果Scheduler直接使用Job,就会存在对同一个Job实例并发访问的问题。而JobDetail & Job 方式,sheduler每次执行,都会根据JobDetail创建一个新的Job实例,这样就可以规避并发访问的问题。

    Quartz API

    Quartz的API的风格在2.x以后,采用的是DSL风格(通常意味着fluent interface风格),就是示例中newTrigger()那一段东西。它是通过Builder实现的,就是以下几个。(** 下面大部分代码都要引用这些Builder ** )

    //job相关的builder
    import static org.quartz.JobBuilder.*;
    
    //trigger相关的builder
    import static org.quartz.TriggerBuilder.*;
    import static org.quartz.SimpleScheduleBuilder.*;
    import static org.quartz.CronScheduleBuilder.*;
    import static org.quartz.DailyTimeIntervalScheduleBuilder.*;
    import static org.quartz.CalendarIntervalScheduleBuilder.*;
    
    //日期相关的builder
    import static org.quartz.DateBuilder.*;
    

    DSL风格写起来会更加连贯,畅快,而且由于不是使用setter的风格,语义上会更容易理解一些。对比一下:

    JobDetail jobDetail=new JobDetailImpl("jobDetail1","group1",HelloQuartz.class);
    jobDetail.getJobDataMap().put("name", "quartz");
    
    SimpleTriggerImpl trigger=new SimpleTriggerImpl("trigger1","group1");
    trigger.setStartTime(new Date());
    trigger.setRepeatInterval(1);
    trigger.setRepeatCount(-1);
    

    关于name和group

    JobDetail和Trigger都有name和group。

    name是它们在这个sheduler里面的唯一标识。如果我们要更新一个JobDetail定义,只需要设置一个name相同的JobDetail实例即可。

    group是一个组织单元,sheduler会提供一些对整组操作的API,比如 scheduler.resumeJobs()。

    Trigger

    在开始详解每一种Trigger之前,需要先了解一下Trigger的一些共性。

    StartTime & EndTime

    startTime和endTime指定的Trigger会被触发的时间区间。在这个区间之外,Trigger是不会被触发的。

    ** 所有Trigger都会包含这两个属性 **

    优先级(Priority)

    当scheduler比较繁忙的时候,可能在同一个时刻,有多个Trigger被触发了,但资源不足(比如线程池不足)。那么这个时候比剪刀石头布更好的方式,就是设置优先级。优先级高的先执行。

    需要注意的是,优先级只有在同一时刻执行的Trigger之间才会起作用,如果一个Trigger是9:00,另一个Trigger是9:30。那么无论后一个优先级多高,前一个都是先执行。

    优先级的值默认是5,当为负数时使用默认值。最大值似乎没有指定,但建议遵循Java的标准,使用1-10,不然鬼才知道看到【优先级为10】是时,上头还有没有更大的值。

    Misfire(错失触发)策略

    类似的Scheduler资源不足的时候,或者机器崩溃重启等,有可能某一些Trigger在应该触发的时间点没有被触发,也就是Miss Fire了。这个时候Trigger需要一个策略来处理这种情况。每种Trigger可选的策略各不相同。

    这里有两个点需要重点注意:

    • MisFire的触发是有一个阀值,这个阀值是配置在JobStore的。比RAMJobStore是org.quartz.jobStore.misfireThreshold。只有超过这个阀值,才会算MisFire。小于这个阀值,Quartz是会全部重新触发。

    所有MisFire的策略实际上都是解答两个问题:

    1. 已经MisFire的任务还要重新触发吗?
    2. 如果发生MisFire,要调整现有的调度时间吗?

    比如SimpleTrigger的MisFire策略有:

    • MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY

      这个不是忽略已经错失的触发的意思,而是说忽略MisFire策略。它会在资源合适的时候,重新触发所有的MisFire任务,并且不会影响现有的调度时间。

      比如,SimpleTrigger每15秒执行一次,而中间有5分钟时间它都MisFire了,一共错失了20个,5分钟后,假设资源充足了,并且任务允许并发,它会被一次性触发。

      这个属性是所有Trigger都适用。

    • MISFIRE_INSTRUCTION_FIRE_NOW

      忽略已经MisFire的任务,并且立即执行调度。这通常只适用于只执行一次的任务。

    • MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT

      将startTime设置当前时间,立即重新调度任务,包括的MisFire的

    • MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT

      类似MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT,区别在于会忽略已经MisFire的任务

    • MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT

      在下一次调度时间点,重新开始调度任务,包括的MisFire的

    • MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT

      类似于MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT,区别在于会忽略已经MisFire的任务。

    • MISFIRE_INSTRUCTION_SMART_POLICY

      所有的Trigger的MisFire默认值都是这个,大致意思是“把处理逻辑交给聪明的Quartz去决定”。基本策略是,

      1. 如果是只执行一次的调度,使用MISFIRE_INSTRUCTION_FIRE_NOW
      2. 如果是无限次的调度(repeatCount是无限的),使用MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT
      3. 否则,使用MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT

    MisFire的东西挺繁杂的,可以参考这篇

    Calendar

    这里的Calendar不是jdk的java.util.Calendar,不是为了计算日期的。它的作用是在于补充Trigger的时间。可以排除或加入某一些特定的时间点。

    以”每月25日零点自动还卡债“为例,我们想排除掉每年的2月25号零点这个时间点(因为有2.14,所以2月一定会破产)。这个时间,就可以用Calendar来实现。

    例子:

    AnnualCalendar cal = new AnnualCalendar(); //定义一个每年执行Calendar,精度为天,即不能定义到2.25号下午2:00
    java.util.Calendar excludeDay = new GregorianCalendar();
    excludeDay.setTime(newDate().inMonthOnDay(2, 25).build());
    cal.setDayExcluded(excludeDay, true);  //设置排除2.25这个日期
    scheduler.addCalendar("FebCal", cal, false, false); //scheduler加入这个Calendar
    
    //定义一个Trigger
    Trigger trigger = newTrigger().withIdentity("trigger1", "group1") 
        .startNow()//一旦加入scheduler,立即生效
        .modifiedByCalendar("FebCal") //使用Calendar !!
        .withSchedule(simpleSchedule()
            .withIntervalInSeconds(1) 
            .repeatForever()) 
        .build();
    

    Quartz体贴地为我们提供以下几种Calendar,注意,所有的Calendar既可以是排除,也可以是包含,取决于:

    • HolidayCalendar。指定特定的日期,比如20140613。精度到天。
    • DailyCalendar。指定每天的时间段(rangeStartingTime, rangeEndingTime),格式是HH:MM[:SS[:mmm]]。也就是最大精度可以到毫秒。
    • WeeklyCalendar。指定每星期的星期几,可选值比如为java.util.Calendar.SUNDAY。精度是天。
    • MonthlyCalendar。指定每月的几号。可选值为1-31。精度是天
    • AnnualCalendar。 指定每年的哪一天。使用方式如上例。精度是天。
    • CronCalendar。指定Cron表达式。精度取决于Cron表达式,也就是最大精度可以到秒。

    Trigger实现类

    Quartz有以下几种Trigger实现:

    SimpleTrigger

    指定从某一个时间开始,以一定的时间间隔(单位是毫秒)执行的任务。

    它适合的任务类似于:9:00 开始,每隔1小时,执行一次。

    它的属性有:

    • repeatInterval 重复间隔
    • repeatCount 重复次数。实际执行次数是 repeatCount+1。因为在startTime的时候一定会执行一次。** 下面有关repeatCount 属性的都是同理。 **

    例子:

    simpleSchedule()
            .withIntervalInHours(1) //每小时执行一次
            .repeatForever() //次数不限
            .build();
    
    simpleSchedule()
        .withIntervalInMinutes(1) //每分钟执行一次
        .withRepeatCount(10) //次数为10次
        .build();
    

    CalendarIntervalTrigger

    类似于SimpleTrigger,指定从某一个时间开始,以一定的时间间隔执行的任务。 但是不同的是SimpleTrigger指定的时间间隔为毫秒,没办法指定每隔一个月执行一次(每月的时间间隔不是固定值),而CalendarIntervalTrigger支持的间隔单位有秒,分钟,小时,天,月,年,星期

    相较于SimpleTrigger有两个优势:1、更方便,比如每隔1小时执行,你不用自己去计算1小时等于多少毫秒。 2、支持不是固定长度的间隔,比如间隔为月和年。但劣势是精度只能到秒。

    它适合的任务类似于:9:00 开始执行,并且以后每周 9:00 执行一次

    它的属性有:

    • interval 执行间隔
    • intervalUnit 执行间隔的单位(秒,分钟,小时,天,月,年,星期)

    例子:

    calendarIntervalSchedule()
        .withIntervalInDays(1) //每天执行一次
        .build();
    
    calendarIntervalSchedule()
        .withIntervalInWeeks(1) //每周执行一次
        .build();
    

    DailyTimeIntervalTrigger

    指定每天的某个时间段内,以一定的时间间隔执行任务。并且它可以支持指定星期。

    它适合的任务类似于:指定每天9:00 至 18:00 ,每隔70秒执行一次,并且只要周一至周五执行。

    它的属性有:

    • startTimeOfDay 每天开始时间
    • endTimeOfDay 每天结束时间
    • daysOfWeek 需要执行的星期
    • interval 执行间隔
    • intervalUnit 执行间隔的单位(秒,分钟,小时,天,月,年,星期)
    • repeatCount 重复次数

    例子:

    dailyTimeIntervalSchedule()
        .startingDailyAt(TimeOfDay.hourAndMinuteOfDay(9, 0)) //第天9:00开始
        .endingDailyAt(TimeOfDay.hourAndMinuteOfDay(16, 0)) //16:00 结束 
        .onDaysOfTheWeek(MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY) //周一至周五执行
        .withIntervalInHours(1) //每间隔1小时执行一次
        .withRepeatCount(100) //最多重复100次(实际执行100+1次)
        .build();
    
    dailyTimeIntervalSchedule()
        .startingDailyAt(TimeOfDay.hourAndMinuteOfDay(9, 0)) //第天9:00开始
        .endingDailyAfterCount(10) //每天执行10次,这个方法实际上根据 startTimeOfDay+interval*count 算出 endTimeOfDay
        .onDaysOfTheWeek(MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY) //周一至周五执行
        .withIntervalInHours(1) //每间隔1小时执行一次
        .build();
    

    CronTrigger

    适合于更复杂的任务,它支持类型于Linux Cron的语法(并且更强大)。基本上它覆盖了以上三个Trigger的绝大部分能力(但不是全部)—— 当然,也更难理解。

    它适合的任务类似于:每天0:00,9:00,18:00各执行一次。

    它的属性只有:

    • Cron表达式。但这个表示式本身就够复杂了。下面会有说明。

    例子:

    cronSchedule("0 0/2 8-17 * * ?") // 每天8:00-17:00,每隔2分钟执行一次
        .build();
    
    cronSchedule("0 30 9 ? * MON") // 每周一,9:30执行一次
    .build();
    
    weeklyOnDayAndHourAndMinute(MONDAY,9, 30) //等同于 0 30 9 ? * MON 
        .build();
    

    Cron表达式

    位置 时间域 允许值 特殊值
    1 0-59 , - * /
    2 分钟 0-59 , - * /
    3 小时 0-23 , - * /
    4 日期 1-31 , - * ? / L W C
    5 月份 1-12 , - * /
    6 星期 1-7 , - * ? / L C #
    7 年份(可选) 1-31 , - * /

    星号():可用在所有字段中,表示对应时间域的每一个时刻,例如, 在分钟字段时,表示“每分钟”;

    问号(?):该字符只在日期和星期字段中使用,它通常指定为“无意义的值”,相当于点位符;

    减号(-):表达一个范围,如在小时字段中使用“10-12”,则表示从10到12点,即10,11,12;

    逗号(,):表达一个列表值,如在星期字段中使用“MON,WED,FRI”,则表示星期一,星期三和星期五;

    斜杠(/):x/y表达一个等步长序列,x为起始值,y为增量步长值。如在分钟字段中使用0/15,则表示为0,15,30和45秒,而5/15在分钟字段中表示5,20,35,50,你也可以使用*/y,它等同于0/y;

    L:该字符只在日期和星期字段中使用,代表“Last”的意思,但它在两个字段中意思不同。L在日期字段中,表示这个月份的最后一天,如一月的31号,非闰年二月的28号;如果L用在星期中,则表示星期六,等同于7。但是,如果L出现在星期字段里,而且在前面有一个数值X,则表示“这个月的最后X天”,例如,6L表示该月的最后星期五;

    W:该字符只能出现在日期字段里,是对前导日期的修饰,表示离该日期最近的工作日。例如15W表示离该月15号最近的工作日,如果该月15号是星期六,则匹配14号星期五;如果15日是星期日,则匹配16号星期一;如果15号是星期二,那结果就是15号星期二。但必须注意关联的匹配日期不能够跨月,如你指定1W,如果1号是星期六,结果匹配的是3号星期一,而非上个月最后的那天。W字符串只能指定单一日期,而不能指定日期范围;

    LW组合:在日期字段可以组合使用LW,它的意思是当月的最后一个工作日;

    井号(#):该字符只能在星期字段中使用,表示当月某个工作日。如6#3表示当月的第三个星期五(6表示星期五,#3表示当前的第三个),而4#5表示当月的第五个星期三,假设当月没有第五个星期三,忽略不触发;

    C:该字符只在日期和星期字段中使用,代表“Calendar”的意思。它的意思是计划所关联的日期,如果日期没有被关联,则相当于日历中所有日期。例如5C在日期字段中就相当于日历5日以后的第一天。1C在星期字段中相当于星期日后的第一天。

    Cron表达式对特殊字符的大小写不敏感,对代表星期的缩写英文大小写也不敏感。

    一些例子:

    表示式 说明
    0 0 12 * * ? 每天12点运行
    0 15 10 ? * * 每天10:15运行
    0 15 10 * * ? 每天10:15运行
    0 15 10 * * ? * 每天10:15运行
    0 15 10 * * ? 2008 在2008年的每天10:15运行
    0 * 14 * * ? 每天14点到15点之间每分钟运行一次,开始于14:00,结束于14:59。
    0 0/5 14 * * ? 每天14点到15点每5分钟运行一次,开始于14:00,结束于14:55。
    0 0/5 14,18 * * ? 每天14点到15点每5分钟运行一次,此外每天18点到19点每5钟也运行一次。
    0 0-5 14 * * ? 每天14:00点到14:05,每分钟运行一次。
    0 10,44 14 ? 3 WED 3月每周三的14:10分到14:44,每分钟运行一次。
    0 15 10 ? * MON-FRI 每周一,二,三,四,五的10:15分运行。
    0 15 10 15 * ? 每月15日10:15分运行。
    0 15 10 L * ? 每月最后一天10:15分运行。
    0 15 10 ? * 6L 每月最后一个星期五10:15分运行。
    0 15 10 ? * 6L 2007-2009 在2007,2008,2009年每个月的最后一个星期五的10:15分运行。
    0 15 10 ? * 6#3 每月第三个星期五的10:15分运行。

    JobDetail & Job

    JobDetail是任务的定义,而Job是任务的执行逻辑。在JobDetail里会引用一个Job Class定义。一个最简单的例子

    public class JobTest {
        public static void main(String[] args) throws SchedulerException, IOException {
               JobDetail job=newJob()
                   .ofType(DoNothingJob.class) //引用Job Class
                   .withIdentity("job1", "group1") //设置name/group
                   .withDescription("this is a test job") //设置描述
                   .usingJobData("age", 18) //加入属性到ageJobDataMap
                   .build();
    
               job.getJobDataMap().put("name", "quertz"); //加入属性name到JobDataMap
    
               //定义一个每秒执行一次的SimpleTrigger
               Trigger trigger=newTrigger()
                       .startNow()
                       .withIdentity("trigger1")
                       .withSchedule(simpleSchedule()
                           .withIntervalInSeconds(1)
                           .repeatForever())
                       .build();
    
               Scheduler sche=StdSchedulerFactory.getDefaultScheduler();
               sche.scheduleJob(job, trigger);
    
               sche.start();
    
               System.in.read();
    
               sche.shutdown();
        }
    }
    
    
    public class DoNothingJob implements Job {
        public void execute(JobExecutionContext context) throws JobExecutionException {
            System.out.println("do nothing");
        }
    }
    

    从上例我们可以看出,要定义一个任务,需要干几件事:

    1. 创建一个org.quartz.Job的实现类,并实现实现自己的业务逻辑。比如上面的DoNothingJob。
    2. 定义一个JobDetail,引用这个实现类
    3. 加入scheduleJob

    Quartz调度一次任务,会干如下的事:

    1. JobClass jobClass=JobDetail.getJobClass()
    2. Job jobInstance=jobClass.newInstance()。所以Job实现类,必须有一个public的无参构建方法。
    3. jobInstance.execute(JobExecutionContext context)。JobExecutionContext是Job运行的上下文,可以获得Trigger、Scheduler、JobDetail的信息。

    也就是说,每次调度都会创建一个新的Job实例,这样的好处是有些任务并发执行的时候,不存在对临界资源的访问问题——当然,如果需要共享JobDataMap的时候,还是存在临界资源的并发访问的问题。

    JobDataMap

    Job都次都是newInstance的实例,那我怎么传值给它? 比如我现在有两个发送邮件的任务,一个是发给"liLei",一个发给"hanmeimei",不能说我要写两个Job实现类LiLeiSendEmailJob和HanMeiMeiSendEmailJob。实现的办法是通过JobDataMap。

    每一个JobDetail都会有一个JobDataMap。JobDataMap本质就是一个Map的扩展类,只是提供了一些更便捷的方法,比如getString()之类的。

    我们可以在定义JobDetail,加入属性值,方式有二:

    newJob().usingJobData("age", 18) //加入属性到ageJobDataMap
    
     or
    
     job.getJobDataMap().put("name", "quertz"); //加入属性name到JobDataMap
    

    然后在Job中可以获取这个JobDataMap的值,方式同样有二:

    public class HelloQuartz implements Job {
        private String name;
    
        public void execute(JobExecutionContext context) throws JobExecutionException {
            JobDetail detail = context.getJobDetail();
            JobDataMap map = detail.getJobDataMap(); //方法一:获得JobDataMap
            System.out.println("say hello to " + name + "[" + map.getInt("age") + "]" + " at "
                               + new Date());
        }
    
        //方法二:属性的setter方法,会将JobDataMap的属性自动注入
        public void setName(String name) { 
            this.name = name;
        }
    }
    

    对于同一个JobDetail实例,执行的多个Job实例,是共享同样的JobDataMap,也就是说,如果你在任务里修改了里面的值,会对其他Job实例(并发的或者后续的)造成影响。

    除了JobDetail,Trigger同样有一个JobDataMap,共享范围是所有使用这个Trigger的Job实例。

    Job并发

    Job是有可能并发执行的,比如一个任务要执行10秒中,而调度算法是每秒中触发1次,那么就有可能多个任务被并发执行。

    有时候我们并不想任务并发执行,比如这个任务要去”获得数据库中所有未发送邮件的名单“,如果是并发执行,就需要一个数据库锁去避免一个数据被多次处理。这个时候一个@DisallowConcurrentExecution解决这个问题。

    就是这样

    public class DoNothingJob implements Job {
        @DisallowConcurrentExecution
        public void execute(JobExecutionContext context) throws JobExecutionException {
            System.out.println("do nothing");
        }
    }
    

    注意,@DisallowConcurrentExecution是对JobDetail实例生效,也就是如果你定义两个JobDetail,引用同一个Job类,是可以并发执行的。

    JobExecutionException

    Job.execute()方法是不允许抛出除JobExecutionException之外的所有异常的(包括RuntimeException),所以编码的时候,最好是try-catch住所有的Throwable,小心处理。

    其他属性

    • Durability(耐久性?)

      如果一个任务不是durable,那么当没有Trigger关联它的时候,它就会被自动删除。

    • RequestsRecovery

      如果一个任务是"requests recovery",那么当任务运行过程非正常退出时(比如进程崩溃,机器断电,但不包括抛出异常这种情况),Quartz再次启动时,会重新运行一次这个任务实例。

      可以通过JobExecutionContext.isRecovering()查询任务是否是被恢复的。

    Scheduler

    Scheduler就是Quartz的大脑,所有任务都是由它来设施。

    Schduelr包含一个两个重要组件: JobStore和ThreadPool。

    JobStore是会来存储运行时信息的,包括Trigger,Schduler,JobDetail,业务锁等。它有多种实现RAMJob(内存实现),JobStoreTX(JDBC,事务由Quartz管理),JobStoreCMT(JDBC,使用容器事务),ClusteredJobStore(集群实现)、TerracottaJobStore(什么是Terractta)。

    ThreadPool就是线程池,Quartz有自己的线程池实现。所有任务的都会由线程池执行。

    SchedulerFactory

    SchdulerFactory,顾名思义就是来用创建Schduler了,有两个实现:DirectSchedulerFactory和 StdSchdulerFactory。前者可以用来在代码里定制你自己的Schduler参数。后者是直接读取classpath下的quartz.properties(不存在就都使用默认值)配置来实例化Schduler。通常来讲,我们使用StdSchdulerFactory也就足够了。

    SchdulerFactory本身是支持创建RMI stub的,可以用来管理远程的Scheduler,功能与本地一样,可以远程提交个Job什么的。

    DirectSchedulerFactory的创建接口

        /**
         * Same as
         * {@link DirectSchedulerFactory#createScheduler(ThreadPool threadPool, JobStore jobStore)},
         * with the addition of specifying the scheduler name and instance ID. This
         * scheduler can only be retrieved via
         * {@link DirectSchedulerFactory#getScheduler(String)}
         *
         * @param schedulerName
         *          The name for the scheduler.
         * @param schedulerInstanceId
         *          The instance ID for the scheduler.
         * @param threadPool
         *          The thread pool for executing jobs
         * @param jobStore
         *          The type of job store
         * @throws SchedulerException
         *           if initialization failed
         */
        public void createScheduler(String schedulerName,
                String schedulerInstanceId, ThreadPool threadPool, JobStore jobStore)
            throws SchedulerException;
    

    StdSchdulerFactory的配置例子, 更多配置,参考Quartz配置指南

    org.quartz.scheduler.instanceName = DefaultQuartzScheduler
    org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
    org.quartz.threadPool.threadCount = 10 
    org.quartz.threadPool.threadPriority = 5
    org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
    org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore

    这里未讲的稍微高级的主题

    参考

    标签: quartzjava

    展开全文
  • 通常的做法就是先形成时间内连续时间间隔的记录集,再跟数据库里的查询结果连接就可以了。 下面给出查询出时间内连续时间间隔的SQL语句: SELECT to_date('2013-10-01', 'yyyy-mm-dd') +

    在实际工作中,有时候要按时间统计一些数据,但数据库里的数据不一定是连续的,按时间分组的话,就会形成时间断档,为了让显示的结果能形成连续的时间记录,

    通常的做法就是先形成一个一段时间内连续时间间隔的记录集,再跟数据库里的查询结果连接就可以了。

    下面给出查询出一段时间内连续时间间隔的SQL语句:

    SELECT to_date('2013-10-01', 'yyyy-mm-dd') +
           numtodsinterval(rownum - 1, 'hour')
      FROM DUAL
    CONNECT BY ROWNUM <= ((to_date('2013-10-02', 'yyyy-mm-dd') -
               to_date('2013-10-01', 'yyyy-mm-dd') + 1) * 24)
    

    结果如下:

    1	2013/10/1
    2	2013/10/1 1:00:00
    3	2013/10/1 2:00:00
    4	2013/10/1 3:00:00
    5	2013/10/1 4:00:00
    6	2013/10/1 5:00:00
    7	2013/10/1 6:00:00
    8	2013/10/1 7:00:00
    9	2013/10/1 8:00:00
    10	2013/10/1 9:00:00
    11	2013/10/1 10:00:00
    12	2013/10/1 11:00:00
    13	2013/10/1 12:00:00
    14	2013/10/1 13:00:00
    15	2013/10/1 14:00:00
    16	2013/10/1 15:00:00
    17	2013/10/1 16:00:00
    18	2013/10/1 17:00:00
    19	2013/10/1 18:00:00
    20	2013/10/1 19:00:00
    21	2013/10/1 20:00:00
    22	2013/10/1 21:00:00
    23	2013/10/1 22:00:00
    24	2013/10/1 23:00:00
    25	2013/10/2
    26	2013/10/2 1:00:00
    27	2013/10/2 2:00:00
    28	2013/10/2 3:00:00
    29	2013/10/2 4:00:00
    30	2013/10/2 5:00:00
    31	2013/10/2 6:00:00
    32	2013/10/2 7:00:00
    33	2013/10/2 8:00:00
    34	2013/10/2 9:00:00
    35	2013/10/2 10:00:00
    36	2013/10/2 11:00:00
    37	2013/10/2 12:00:00
    38	2013/10/2 13:00:00
    39	2013/10/2 14:00:00
    40	2013/10/2 15:00:00
    41	2013/10/2 16:00:00
    42	2013/10/2 17:00:00
    43	2013/10/2 18:00:00
    44	2013/10/2 19:00:00
    45	2013/10/2 20:00:00
    46	2013/10/2 21:00:00
    47	2013/10/2 22:00:00
    48	2013/10/2 23:00:00
    


    展开全文
  • 前言 点赞在,养成习惯。 点赞收藏,人生辉煌。 ... HashMap系列文章 第篇 HashMap源码中...第篇 HashMap源码中的resize扩容方法除了扩容还有个用途你真的知道吗? 第五篇 留一半清醒、留一半醉!!!HashMap中

    前言

    点赞在看,养成习惯。

    点赞收藏,人生辉煌。

    HashMap系列文章

    第一篇 HashMap源码中的成员变量你还不懂? 来来来!!!整理好的成员变量源码解析

    第二篇 撸啊撸,再次撸HashMap源码,踩坑源码中构造方法!!!每次都有收获

    第三篇 MoxiMoxi !!!你看过HashMap中的put方法的源码吗?

    第四篇 HashMap源码中的resize扩容方法除了扩容还有一个用途你真的知道吗?

    第五篇 留一半清醒、留一半醉!!!HashMap中treeifyBin、treeify源码解析

    第六篇 隔一段时间撸一次,特别香,HashMap中remove、getOrDefault源码,一遍一遍、又一遍

    删除方法public V remove(Object key)

    案例演示

    测试删除首节点
    @Test
    public void test_remove_map(){
    	HashMap<Integer, String> map = new HashMap<>();
    	map.put(1, "aaa");
    	map.put(2, "bbb");
    	map.put(2, "bbb111");
    	map.put(3, "ccc0333");
    
    	map.forEach((k, v) -> System.out.println("k: " + k + "    v: " + v));
    	System.out.println("=========================");
    	map.remove(2);// 执行remove方法
    	map.forEach((k, v) -> System.out.println("k: " + k + "    v: " + v));
    }
    
    案例演示结果
    k: 1    v: aaa
    k: 2    v: bbb111
    k: 3    v: ccc0333
    =========================
    k: 1    v: aaa
    k: 3    v: ccc0333
    
    测试删除链表节点
    @Test
    public void test_map_hash_remove() {
    	HashMap<String, Integer> map = new HashMap<>();
    	for (int i = 0; i < 64; i++){
    		map.put("BB" + i, i);
    	}
    	System.out.println(map.size());
      // 构造8个哈希碰撞,会产生链表结构
    	map.put("3Qj", 800);
    	map.put("2pj", 801);
    	map.put("2qK", 802);
    	map.put("2r,", 803);
    	map.put("3RK", 804);
    	map.put("3S,", 805);
    	map.put("42j", 806);
    	map.put("43K", 807);
      // 删除这个是删除的链表中的节点
    	map.remove("43K");
    }
    
    测试删除树节点
    @Test
    public void test_map_hash_remove() {
    	HashMap<String, Integer> map = new HashMap<>();
    	for (int i = 0; i < 64; i++){
    		map.put("BB" + i, i);
    	}
    	System.out.println(map.size());
      // 构造8个哈希碰撞,会转换为红黑树
    	map.put("3Qj", 800);
    	map.put("2pj", 801);
    	map.put("2qK", 802);
    	map.put("2r,", 803);
    	map.put("3RK", 804);
    	map.put("3S,", 805);
    	map.put("42j", 806);
    	map.put("43K", 807);
    	map.put("44,", 808);
      // 删除一个🌲节点
    	map.remove("44,");
    }
    

    源码解析

    根据指定key的方法remove
    // 根据指定的key删除元素,返回被删除的元素或者null
    public V remove(Object key) {
      // 定义一个节点变量,用来存储要被删除的节点(键值对)
    	Node<K,V> e;
      // 调用removeNode方法根据给定的key获取node,获取的node为空,则返回空。获得的node不为空返回节点的value。
    	return (e = removeNode(hash(key), key, null, false, true)) == null ?
    			null : e.value;
    }
    
    根据指定的key和value删除元素
    // 返回是否删除成功
    @Override
    public boolean remove(Object key, Object value) {
      // 调用removeNode方法删除元素
    	return removeNode(hash(key), key, value, true, true) != null;
    }
    
    删除节点关键方法removeNode
    final Node<K,V> removeNode(int hash, Object key, Object value,
    						   boolean matchValue, boolean movable) {
    	Node<K,V>[] tab; Node<K,V> p; int n, index;
      // 当前集合不为空,并且根据给定的hash值是可以找到桶
    	if ((tab = table) != null && (n = tab.length) > 0 &&
    			(p = tab[index = (n - 1) & hash]) != null) {
    		Node<K,V> node = null, e; K k; V v;
        // 如果桶上的节点就是要找的key,则将node指向该节点
    		if (p.hash == hash &&
    				((k = p.key) == key || (key != null && key.equals(k))))
          // 将要被删除的节点赋值给node
    			node = p;
        // 到这,说明桶上的第一个节点不匹配,判断当前节点的下一个节点是否为空
    		// 如果没有next节点,说明该节点所在位置没有发生hash碰撞, 否则发生了哈希碰撞
        else if ((e = p.next) != null) {
          // 判断当前节点类型是否是树节点
    			if (p instanceof TreeNode)
            // 从红黑树中获取要删除的节点赋值给node 
    				node = ((TreeNode<K,V>)p).getTreeNode(hash, key);
          //  // 判断是否以链表的⽅式处理hash冲突,是的话则通过遍历链表来寻找要删除的节点
    			else {
            // 循环遍历这个链表
    				do {
              // 根据给定的hash值和key判断下一个节点是否是要删除的节点
    					if (e.hash == hash &&
    							((k = e.key) == key ||
    									(key != null && key.equals(k)))) {
                // 将要删除的节点赋值给node
    						node = e;
                // 跳出循环
    						break;
    					}
              // 代码执行到这,说明未匹配上
              // 把当前节点p指向e,这一步是让p存储的永远是下一次循环里e的父节点,如果下一次e匹配上了,那么p就是node的父节点
              // 如果循环中找到了要被删除的节点,那么这个p节点,
    					p = e;
    				} while ((e = e.next) != null);
    			}
    		}
        // 如果node不为空,说明根据key匹配到了要删除的节点
    		if (node != null && (!matchValue || (v = node.value) == value ||
    				(value != null && value.equals(v)))) {
          // 判断要删除的节点是否是树节点
    			if (node instanceof TreeNode)
            // 通过调用红黑树的方法来删除节点
    				((TreeNode<K,V>)node).removeTreeNode(this, tab, movable);
          // 如果该节点不是树节点,node == p:说明该node节点就是首节点,当前桶里就一个节点
    			else if (node == p)
            // 删除的是首节点,那么直接将节点数组对应位置指向到下一个节点。
    				tab[index] = node.next;
    			else
            // 删除链表节点。删除元素的操作是将被删除元素的父节点,指向被删除节点的下一个节点
    				p.next = node.next;
          // 记录修改次数
    			++modCount;
          // 变动的数量
    			--size;
    			afterNodeRemoval(node);
          // 返回被删除的节点
    			return node;
    		}
    	}
      // 没有被删除的元素返回null 
    	return null;
    }
    

    源码总结

    - 当前集合不为空,并且根据当前的key计算得到的索引拿到节点返回被删除的节点。
    
    	1、要删除的节点为首节点并且这个节点没有下一个节点,删除也就是将这个节点赋值为null.
    
    	2、要删除的节点为红黑树节点,根据key和key对应的哈希值从红黑树中获取要被删除的节点。
    
    	3、要删除的节点为链表节点,循环遍历这个链表,如果获取到要删除的节点跳出循环,删除元素的操作是将被删除元素的父节点,指向被删除节点的下一个节点。
    
    - 当前集合为空,或者无法根据当前的key计算得到的索引拿到节点,返回null。
    

    public V getOrDefault(Object key, V defaultValue)获取指定元素,如果拿不到返回我们自定义的val

    案例演示

    @Test
    public void test_map_hash_getDefaultOf() {
    	HashMap<Integer, String> map = new HashMap<>();
    	map.put(1, "aaa");
    	map.put(2, "bbb");
    	map.put(3, "bbb111");
      // 获取集合中存在的元素
    	String t = map.getOrDefault(3, "fafafa");
      // 获取集合中不存在的元素
    	String d = map.getOrDefault(4, "lalala");
    	System.out.println("集合中包含:" + t + "    集合中不包含:" + d);
      // 集合中包含:bbb111    集合中不包含:lalala
    }
    

    源码解析

    getOrDefault源码解析
    // 根据指定的key获取对应的val,如果拿到val,则返回拿到的val。否则返回我们给定的默认defaultValue
    @Override
    public V getOrDefault(Object key, V defaultValue) {
      // 用于接收要获取到的node节点
    	Node<K,V> e;
      // 获取到节点返回,节点的val,否则返回我们自定义的defaultValue
    	return (e = getNode(hash(key), key)) == null ? defaultValue : e.value;
    }
    
    getNode方法的源码解析
    // 根据指定的key和val获取节点
    final Node<K,V> getNode(int hash, Object key) {
    	Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
      // 如果哈希表不不为空并且key对应的桶上不不为空
    	if ((tab = table) != null && (n = tab.length) > 0 &&
    			(first = tab[(n - 1) & hash]) != null) {
        // 判断数组元素是否相等
        // 根据索引的位置检查第一个节点
        // 注意:总是检查第一个节点
    		if (first.hash == hash && // always check first node
    				((k = first.key) == key || (key != null && key.equals(k))))
          // 返回这个节点
    			return first;
        // 如果不是第一个节点,判断是否有后续节点
    		if ((e = first.next) != null) {
          // 判断是否是红黑树,是的话调用红⿊树中的getTreeNode方法获取节点
    			if (first instanceof TreeNode)
    				return ((TreeNode<K,V>)first).getTreeNode(hash, key);
    			do {
            // 不是红黑树的话,那就是链表结构了,通过循环的方法判断链表中是否存在该key
    				if (e.hash == hash &&
    						((k = e.key) == key || (key != null && key.equals(k))))
              // 返回这个节点
    					return e;
    			} while ((e = e.next) != null);
    		}
    	}
      // 未获取到节点返回null
    	return null;
    }
    
    谢谢点赞
    • 创作不易, 非常欢迎大家的点赞、评论和关注(^_−)☆
    • 你的点赞、评论以及关注是对我最大的支持和鼓励
    • 是我继续创作高质量博客的动力 !!!
    展开全文
  • 在上篇文章(RMAN备份与恢复之UNDO表空间丢失)中,我们讲到UNDO表空间丢失怎么处理,本文讲解基于时间点的不完全恢复。
  • Java Calendar 日历类的时间操作,这也许是 Java 环境下创建和管理日历及操作时间最简单的个方案了,示范代码也很简单。 演示了获取时间,日期时间的累加和累减,以及日期时间的比较。 原文地址:blog.csdn.net/...
  • mysql 基于时间点恢复

    千次阅读 2015-09-24 19:07:16
    MySQL基于时间点恢复(PITR) MySQL的PITR主要是通过mysqldump来做全备,然后通过log-bin来恢复到某个时间点,达到PITR的目的 确认log_bin是否打开 mysql> show global variables like 'log_bin'; +---------------...
  • 两者有此不同,在Linux下没有创建时间的概念,也就是不能知道文件的建立时间,但如果文件建立后就没有修改过,修改时间=建立时间;如果文件建立后,状态就没有改动过,那么状态改动时间=建立时间;如果文件建立...
  • 不是很严谨的以下图反推,个bit的时间正好就是4usec。波特率的单位应该就是比特每秒bit/s(bsp不好说明到底是bit 还是 byte) 每个字节包含11个bit,也就44usec,大概就是25k byte/s。也就是说每秒可以发送25k个...
  • 44.Oracle数据库SQL开发之 日期和时间的存储与处理——理解时区 欢迎转载,转载请标明出处: ORACLE 9i引入了种新特性,可以表示不同的时区。 格林威治时间一度被称为格林威治标准时间(Green Mean Time,GMT...
  • 磐创AI分享作者 | SAURABH JAJU编译 | Flin来源 | analyticsvidhya介绍时间序列预测与建模在数据分析中起着重要的作用。时间序列分析是统计学...
  • 要实现informix的指定时间点数据恢复,只有2个方法,个是onbar,个是ontape,只有onbar才具有指定时间点恢复的功能,但onbar的配置相对复杂,而且限制不小。相对来说,ontape虽然没有提供指定时间点恢复的功能,...
  • 44. 数据结构笔记之弗洛伊德Floyd算法 “希望是厄运的忠实的姐妹。 --普希金” 继续来下数据结构图中的个算法,这个算法来自图灵奖得主。 1. Floyd算法介绍 Floyd算法又称为插法,是种用于寻找...
  • 1.关于BadVPN的使用问题和OpenVPN相反,BadVPN几乎没有除了配置隧道之外的任何东西,这些被排除了内容中最重要的应该就是路由了。OpenVPN中就有关于路由的很多配置,还可以从服务端往客户端推送路由,这简直太方便了...
  • 总结以下三种方法,实现c#每隔时间执行代码: 方法:调用线程执行方法,在方法中实现死循环,每个循环Sleep设定时间; 方法二:使用System.Timers.Timer类; 方法三:使用System.Threading.Timer; ...
  • * 根据时间区间,按月份拆分成多个时间段 * @author lxg * * 2016年9月5日下午6:18:36 */ public class SplitDateUtil { @Test public void demo (){ List<KeyValueForDate> list = ...
  • 通常会统计某时间内每天数据总计变化趋势调整营销策略。下面来以下案例。案例在电商平台中通常会有订单表,记录所有订单信息。现在我们需要统计某个月份每天订单数及销售金额数据从而绘制出如下统计图,进行...
  • Linux自带了ntp服务 -- /etc/init.d/ntpd,这个服务不仅可以设置让本机和某台/某些机器做时间同步,他本身还可以扮演个time server的角色,让其他机器和他同步时间。配置文件就是/etc/ntp.conf。  为了测试,在...
  • 总结以下三种方法,实现c#每隔时间执行代码: 方法:调用线程执行方法,在方法中实现死循环,每个循环Sleep设定时间; 方法二:使用System.Timers.Timer类; 方法三:使用System.Threading.Timer; ...
  • 4、前个小时时间 ? 1 select date_sub(now(), interval 1 hour ); 5、后一个小时时间 ? 1 select date_sub(now(), interval -1 hour ); ...
  • 一元次方程的求解

    千次阅读 2019-11-09 10:59:20
    一元次方程的求解0....要是直接放入C++中,通过解析解来实时求它的解甚至会比求解一元次方程花费的时间更多。于是另谋出路,查阅资料如何求解一元次方程。 1.方法 Ferrari方法,这也是最容易Googl...
  • 、在Python中,时间主要有三种表示形式, 1.时间戳(TimeStamp):1970年1月1日之后的秒 2.时间元组格式化形式 包含了:年、日、星期 得到time.struct_time(tm_year=2017, tm_mon=10, tm_mday=14…) ...
  • java设置job时间 例:每小时

    千次阅读 2019-05-29 15:24:01
    每天每小时(整点)执行次:0 0 0/1 * * ? 例1:每隔5秒执行次:*/5 * * * * ?...例3:每天半夜1230分执行次:0 30 0 * * ? (注意日期域为0不是24) 每天凌晨1执行次:0 0 1 * * ? 每天上午10:15执...
  • js知识汇总

    万次阅读 多人点赞 2019-11-03 20:58:42
    2.种计算机客户端脚本语言,主要在Web浏览器解释执行。 3.浏览器中Javascript,用于与用户交互,以及实现页面中各种动态特效 4.在HTML文件中,任何JavaScript代码必须放到<script>标签中 5.把JavaScript...
  • pandas时间序列

    千次阅读 2018-07-25 22:12:35
    很多时间时间序列是固定频率的, 也就是说, 数据是根据某种规律定期出现的(比如每15秒。。。。)。时间序列也可以是不定期的。时间序列数据的意义取决于具体的应用场景。主要由以下几种: 1.时间戳;...
  • 前言 近期准备学习了一些流媒体的资料.因此找到了来疯直播这个开源项目,研究了段时间,...于是在来疯直播的基础上,自己添加了个利用tcp推送的代码.. 因为只是个学习demo,所以只用了一些超简单的代码来进行交互.
  • 表示最近的上个进程pid 真正运行统计程序的脚本 cat stat_run.sh STAT_FILE=stat_delay.log echo "" > $STAT_FILE while true; do tail -n10000 perf.log | awk '{print $8}' | grep totalAll | ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 412,205
精华内容 164,882
关键字:

一看时间就是4点44