精华内容
下载资源
问答
  • Linux任务计划、周期性任务执行

    千次阅读 2018-04-03 13:42:23
    Linux任务计划、周期性任务执行atat命令用于在指定时间执行命令。执行结果会通过邮件发送给用户at允许使用一套相当复杂的指定时间的方法。它能够接受在当天的hh:mm(小时:分钟)式的时间指定。假如该时间已过去,...
    
    

    Linux任务计划、周期性任务执行

    at

    at命令用于在指定时间执行命令。执行结果会通过邮件发送给用户

    at允许使用一套相当复杂的指定时间的方法。它能够接受在当天的hh:mm(小时:分钟)式的时间指定。假如该时间已过去,那么就放在第二天执行

    语法

    at(选项)(参数)
        atq: 查询任务列表
        atrm: 删除指定任务
    

    选项

    -f:指定包含具体指令的任务文件;
    -q:指定新任务的队列名称;
    -l:显示待执行任务的列表;
    -d:删除指定的待执行任务;
    -c:查看指定作业的具体内容;
    -m:任务执行完成后向用户发送E-mail。
    

    参数

    日期时间:指定任务执行的日期时间。

    时间格式

    at now+5 minutes    任务在5分钟后运行
    at now+1 hour       任务在1小时候运行
    at now+1 days       任务在1天后运行
    at now+1 weeks      任务在1周后运行
    at midnight         任务在午夜运行
    at 23:30 tomorrow   任务在明天晚上23:30分执行
    at 10:20pm          任务在晚上10:20分执行
    at 23:30 2018-03-31 任务在指定时间执行
    at 5pm +3 days      任务在3天下午5点执行
    

    实例

    • 确保进程atd启用

      [root@localhost tmp]# systemctl start atd
      [root@localhost tmp]# systemctl status atd
      ● atd.service - Job spooling tools
         Loaded: loaded (/usr/lib/systemd/system/atd.service; enabled; vendor preset: enabled)
         Active: active (running) since Sun 2018-04-01 20:58:13 CST; 21h left
       Main PID: 2905 (atd)
         CGroup: /system.slice/atd.service
                 └─2905 /usr/sbin/atd -f
      

    Apr 01 20:58:13 localhost.localdomain systemd[1]: Started Job spooling tools. Apr 01 20:58:13 localhost.localdomain systemd[1]: Starting Job spooling tools...

    • 1分钟后输出当前时间到指定文件

      [root@localhost ~]# at now+1 minutes
      at> date > /tmp/date
      at> <EOT>
      job 7 at Sat Mar 31 23:21:00 2018
      

    crontab

    crontab命令被用来提交和管理用户的需要周期性执行的任务,crond进程每分钟会定期检查是否有要执行的任务,如果有要执行的任务,则自动执行该任务。

    • 系统cron任务:主要用户实现系统自身的维护,手动编辑 :/etc/crontab
    • 用户cron任务:使用crontab命令

    系统cron任务配置文件:/etc/crontab

    [root@localhost tmp]# cat /etc/crontab
    SHELL=/bin/bash
    PATH=/sbin:/bin:/usr/sbin:/usr/bin
    MAILTO=root
    
    # For details see man 4 crontabs
    
    # Example of job definition:
    # .---------------- minute (0 - 59)
    # |  .------------- hour (0 - 23)
    # |  |  .---------- day of month (1 - 31)
    # |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
    # |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
    # |  |  |  |  |
    # *  *  *  *  * user-name  command to be executed
    
    (1) 每一行定义一个周期性任务,共7个字段;
        *  *  *  *  * : 定义周期性时间
        user-name : 运行任务的用户身份
        command to be executed:任务
    (2) 此处的环境变量不同于用户登录后获得的环境,因此,建议命令使用绝对路径,或者自定义PATH环境变量;
    (3) 执行结果邮件发送给MAILTO指定的用户
    

    用户crond配置文件:/var/spool/cron/USERNAME

    SHELL=/bin/bash
    PATH=/sbin:/bin:/usr/sbin:/usr/bin
    MAILTO=root
    
    # For details see man 4 crontabs
    
    # Example of job definition:
    # .---------------- minute (0 - 59)
    # |  .------------- hour (0 - 23)
    # |  |  .---------- day of month (1 - 31)
    # |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
    # |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
    # |  |  |  |  |
    # *  *  *  *  *   command to be executed    
    
    (1) 每行定义一个cron任务,共6个字段;
    (2) 此处的环境变量不同于用户登录后获得的环境,因此,建议命令使用绝对路径,或者自定义PATH环境变量;
    (3) 邮件发送给当前用户;
    

    语法

    crontab(选项)(参数)

    选项

    -e:编辑该用户的计时器设置;
    -l:列出该用户的计时器设置;
    -r:删除该用户的计时器设置;
    -u<用户名称>:指定要设定计时器的用户名称。
    

    参数

    crontab文件:指定包含待执行任务的crontab文件。

    时间表示法

    (1) 特定值;给定时间点有效取值范围内的值;
        注意:day of week和day of month一般不同时使用;
    (2) *:给定时间点上有效取值范围内的所有值;表“每..”
    (3) 离散取值:在时间点上使用逗号分隔的多个值; 
        #,#,#
    (4) 连续取值:“-”在时间点上使用-连接开头和结束
        #-#
    (5) 在指定时间点上,定义步长: 
        /#:#即步长;
    
    注意:
    (1) 指定的时间点不能被步长整除时,其意义将不复存在;
    (2) 最小时间单位为“分钟”,想完成“秒”级任务,得需要额外借助于其它机制;
    定义成每分钟任务:而在利用脚本实现在每分钟之内,循环执行多次;
    

    时间示例

    (1) 3 * * * *:每小时执行一次;每小时的第3分钟;
    (2) 3 4 * * 5:每周执行一次;每周5的4点3分;
    (3) 5 6 7 * *:每月执行一次;每月的7号的6点5分;
    (4) 7 8 9 10 *:每年执行一次;每年的10月9号8点7分;
    (5) 9 8 * * 3,7:每周三和周日;
    (6) 0 8,20 * * 3,7:每周三和每周日的8点和20点
    (7) 0 9-18 * * 1-5:每星期一到星期五,9点-18点,每小时执行一次
    (8) */5 * * * *:每5分钟执行一次某任务;
    (9) * */12 * * * :每12小时执行一次某任务=
    (10)* * * * 2,4,7:每周2、4、7执行某次任务
    

    实例

    • 确保crond启用

      [root@localhost tmp]# systemctl start crond
      [root@localhost tmp]# systemctl status crond
      ● crond.service - Command Scheduler
         Loaded: loaded (/usr/lib/systemd/system/crond.service; enabled; vendor preset: enabled)
         Active: active (running) since Sun 2018-04-01 17:15:48 CST; 17h left
       Main PID: 640 (crond)
         CGroup: /system.slice/crond.service
                 └─640 /usr/sbin/crond -n
      
      Apr 01 17:15:48 localhost.localdomain systemd[1]: Started Command Scheduler.
      Apr 01 17:15:48 localhost.localdomain systemd[1]: Starting Command Scheduler...
      Apr 01 17:15:48 localhost.localdomain crond[640]: (CRON) INFO (RANDOM_DELAY will be scaled with factor 9% ...ed.)
      Apr 01 17:15:48 localhost.localdomain crond[640]: (CRON) INFO (running with inotify support)
      Hint: Some lines were ellipsized, use -l to show in full.
      

    - 每12小时执行一次

    • 每周三凌晨三、五点10分执行某个脚本,输出当前时间,时间格式为 2017-12-28 10:00:00

      [root@localhost tmp]# crontab
      10 3,5 * * 3 /bin/bash /tmp/date.sh
      
      [root@localhost tmp]# crontab -l
      10 3,5 * * 3 /bin/bash /tmp/date.sh
      
      [root@localhost tmp]# cat /var/spool/cron/root 
      10 3,5 * * 3 /bin/bash /tmp/date.sh
    展开全文
  • ruby之 周期性任务

    千次阅读 2013-10-20 18:03:26
     无论是用ruby做系统管理,还是用rails做web开发,都可能遇到周期性任务,它们按照一定时间周期(1小时,2天......)继续地触发。在ruby中,我认为一次性任务使用sidekiq来完成是非常方便的,而周期性的任务就需要...

    1.前言

         无论是用ruby做系统管理,还是用rails做web开发,都可能遇到周期性任务,它们按照一定时间周期(1小时,2天......)持续地触发。在ruby中,我认为一次性任务使用 sidekiq来完成是非常方便的,而周期性的任务就需要用到 wheneversidetiqclockwork等等gem了。

    2.whenever

        首先,whenever是基于linux的cron服务的,所以,在windows平台上没有直接的方法使用该gem。whenever严格来说应该算一个cron的翻译器,将ruby代码翻译为cron脚本,从而将周期性任务转交给cron实际去完成。对于精通cron的shell程序员来说可能不值一提,但对rubyist却不是。首先,我们可以使用ruby语言来书写任务代码,在ruby层面上控制代码,避免了和一些shell脚本的切换;另外,cron命令很强大,但我总是记不住它的命令参数,为了避免一遍一遍去man它的手册,还是ruby语法比较亲民。
        首先,安装whenever:
    $ gem install whenever

       然后切换到任务编写文件夹project下,保证该文件夹下有一个config文件夹。如果是在rails项目中建立whenever任务,则config文件夹已经存在了。
    $ cd /project
    $ wheneverize .

        whenverize命令会在config文件夹下创建schedule.rb文件,我们的任务代码需要在该文件中定义。下面的是schedule.rb文件示例:
    every 3.hours do
      runner "MyModel.some_process"
      rake "my:rake:task"
      command "/usr/bin/my_great_command"
    end
    
    every 1.day, :at => '4:30 am' do
      runner "MyModel.task_to_run_at_four_thirty_in_the_morning"
    end
    
    every :hour do # 常用的简写有: :hour, :day, :month, :year, :reboot
      runner "SomeModel.ladeeda"
    end
    
    every :sunday, :at => '12pm' do # 你可以使用星期几或周末或工作日: :weekend, :weekday
      runner "Task.do_something_great"
    end
    
    every '0 0 27-31 * *' do
      command "echo 'you can use raw cron syntax too'"
    end
    
    # run this task only on servers with the :app role in Capistrano
    # see Capistrano roles section below
    every :day, :at => '12:20am', :roles => [:app] do
      rake "app_server:task"
    end

        如示例代码,whenever默认定义了三种任务类型:runner, rake, command,我们也可以定义自己的任务,比如,下面的代码定义了脱离rails环境,独立执行ruby代码的类型:
    job_type :ruby, "cd :path && /usr/bin/ruby ':task'.rb"
    
    every :hour do
      ruby 'have_a_rest'
    end

       该示例描述了:每个小时会执行一次当前文件夹下的have_a_rest.rb脚本。
       下面看看怎么将任务写入cron服务。
    $ whenever   #不带参数的whenever会显示转换程cron任务的代码,不写入cron任务表
    $ whenever -w #写入cron任务表,开始执行
    $ whenever -c #取消任务

       如果要查看cron任务表,也可以使用linux的命令列出所有cron任务:
    $ crontab -l

    3.sidetiq

           sidetiq是sidekiq的亲兄弟,如果在rails项目中使用sidekiq来处理后台任务,那么就用sidetiq来交付周期性任务也显得比较自然。
           安装sidetiq:
    $ [sudo] gem install sidetiq

          定义周期性任务:
    class MyWorker
      include Sidekiq::Worker
      include Sidetiq::Schedulable
    
      recurrence { daily }
    
      def perform
        # do stuff ...
      end
    end

         sidetiq和sidekiq一样,依赖于redis消息来处理消息。当rails项目启动后,这些周期性任务会自动加载执行。

    4.clockwork

        clockwork和sidetiq一样,也不必依赖于cron,可以适应”跨平台“要求。下面是代码示例(clock.rb):
    require 'clockwork'
    include Clockwork
    
    handler do |job|
      puts "Running #{job}"
    end
    
    every(10.seconds, 'frequent.job')
    every(3.minutes, 'less.frequent.job')
    every(1.hour, 'hourly.job')
    
    every(1.day, 'midnight.job', :at => '00:00')

        启动任务:
    $ clockwork clock.rb
    Starting clock for 4 events: [ frequent.job less.frequent.job hourly.job midnight.job ]
    Triggering frequent.job
       如果要带上rails环境,就在任务文件加入:
    require './config/boot'
    require './config/environment'



    展开全文
  • 任务调度是指基于给定时间点,给定时间间隔或者给定执行次数自动执行任务,简而言之可以理解成周期性执行某一项任务

    引言

    在做Android App开发的过程相信大家都会遇到周期性执行一些任务的需求,比如说每隔一段时间刷新下界面,每隔一段时间刷新下当前的天气情况或者实现类似Windows的若干时间自动播放屏保等等。

    一、概述

    任务调度是指基于给定时间点,给定时间间隔或者给定执行次数自动执行任务,简而言之可以理解成周期性执行某一项任务。

    二、任务调度的实现方式

    通常任务调度机制实现的方式主要有以下几种:Timer、ScheduledExecutor、Handler和其他第三方开源库

    1、Timer

    java.util.Timer是Java语言本身提供的一种最简单实现任务调度的方法,使用起来也很简单,通过对应的api调用即可。Timer 的设计核心是一个 TaskQueue和一个 TaskThread。Timer 将接收到的任务丢到自己的 TaskQueue中,TaskQueue按照 Task 的最初执行时间进行排序。TimerThread 在创建 Timer 时会启动成为一个守护线程,这个守护线程会轮询所有任务,找到一个最近要执行的任务,然后休眠,当到达最近要执行任务的开始时间点,TimerThread 被唤醒并执行该任务。之后 TimerThread 更新最近一个要执行的任务,继续休眠。

    • 继承TimerTask实现具体的作业任务类
    • 重写run方法实现具体的作业操作
    • 构造Timer对象并调用schedule方法传入指定参数即可
    public class PeriodicOperations {
    
            public static void main(String[] args) {
            testTimerWay();
        }
    
        private static void testTimerWay(){
            Timer timer = new Timer(); 
            long delay1 = 1 * 1000; 
            long period1 = 1000; 
            // 从现在开始 1 秒钟之后,每隔 1 秒钟执行一次 job1 
            timer.schedule(new TimerTest("job1"), delay1, period1); 
            long delay2 = 2 * 1000; 
            long period2 = 2000; 
            // 从现在开始 2 秒钟之后,每隔 2 秒钟执行一次 job2 
            timer.schedule(new TimerTest("job2"), delay2, period2); 
        }
    
        static class TimerTest extends TimerTask{
            private String jobName = ""; 
            public TimerTest(String job) {
                super();
                this.jobName=job;
            }
            @Override
            public void run() {
                System.out.println("执行作业:"+jobName);
            }
        }
    }

    这里写图片描述

    Timer机制实现任务调度的核心类是 Timer 和 TimerTask。其中 Timer 负责设定 TimerTask 的起始与间隔执行时间。使用者只需要创建一个 TimerTask 的继承类,实现自己的 run 方法,然后将其丢给 Timer 去执行即可。Timer 的优点在于简单易用,但由于所有任务都是由同一个线程来调度,因此所有任务都是串行执行的,同一时间只能有一个任务在执行,前一个任务的延迟或异常都将会影响到之后的任务,所以不太适合并发类的任务调度

    2、ScheduledExecutor

    为了弥补Timer 的上述缺陷,在Java 5的时候推出了基于线程池设计的 ScheduledExecutor。其设计思想是:每一个被调度的任务都会由线程池中一个线程去执行,因此任务是并发执行的,相互之间不会受到干扰。但需要注意的是只有当任务的执行时间到来时,ScheduedExecutor 才会真正启动一个线程,其余时间 ScheduledExecutor 都是在轮询任务的状态

    • 定义一个作业线程负责实现具体的操作逻辑
    • 创建一个线程池用于管理作业线程
    • 调用线程池的对应方法(ScheduleWithFixedDelay或ScheduleAtFixedRate )启动周期性机制
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.Timer;
    import java.util.TimerTask;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ScheduledExecutorService;
    import java.util.concurrent.TimeUnit;
    
    public class PeriodicOperations {
    
        public static void main(String[] args) {
            testScheduledExecutorWay();
        }
    
        private static void testScheduledExecutorWay(){
            ScheduledExecutorService service = Executors.newScheduledThreadPool(10);//创建线程池的方式有几种,可以根据业务具体选择
    
            long initialDelay1 = 1;
            long period1 = 1;
            // 从现在开始1秒钟之后,每隔1秒钟执行一次job1
            service.scheduleAtFixedRate(
                    new ScheduledExecutorTest("job1"), initialDelay1,
                    period1, TimeUnit.SECONDS);
    
            long initialDelay2 = 1;
            long delay2 = 1;
            // 从现在开始2秒钟之后,每隔2秒钟执行一次job2
            service.scheduleWithFixedDelay(
                    new ScheduledExecutorTest("job2"), initialDelay2,
                    delay2, TimeUnit.SECONDS);
        }
    
        static class ScheduledExecutorTest implements Runnable{
            private String jobName = "";
    
            public ScheduledExecutorTest(String jobName) {
                super();
                this.jobName = jobName;
            }
    
            @Override
            public void run() {
                System.out.println(getNowTime()+"执行作业:" + jobName);
            }
        }
    
        public static String getNowTime(){
            Date now = new Date();
            SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");// 可以方便地修改日期格式
            return dateFormat.format(now);
        }
    }
    

    ScheduledExecutorService 中两种最常用的调度方法 ScheduleAtFixedRate 和 ScheduleWithFixedDelay。其中ScheduleAtFixedRate 每次执行时间为上一次任务开始起向后推一个时间间隔,即每次执行时间为 :initialDelay, initialDelay+period, initialDelay+2*period, …;而ScheduleWithFixedDelay 每次执行时间为上一次任务结束起向后推一个时间间隔,即每次执行时间为:initialDelay, initialDelay+executeTime+delay, initialDelay+2*executeTime+2*delay。所以两种方式异同在于ScheduleAtFixedRate 是基于固定时间间隔进行任务调度ScheduleWithFixedDelay 取决于每次任务执行的时间长短,是基于不固定时间间隔进行任务调度
    这里写图片描述

    3、结合 ScheduledExecutor 和 Calendar 实现复杂任务调度

    无论是Timer 和 ScheduledExecutor 都仅能提供基于开始时间与重复间隔的任务调度,不能实现更加复杂的调度需求。比如说设置每星期二的 16:38:10 执行任务等等,单独使用 Timer 或 ScheduledExecutor 都不能直接实现,但我们可以借助 Calendar 间接实现该功能。

    import java.util.Calendar;
    import java.util.Date;
    import java.util.TimerTask;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ScheduledExecutorService;
    import java.util.concurrent.TimeUnit;
    
    public class ScheduledExceutorTest2 extends TimerTask {
    
        private String jobName = "";
    
        public ScheduledExceutorTest2(String jobName) {
            super();
            this.jobName = jobName;
        }
    
        @Override
        public void run() {
            System.out.println("Date = "+new Date()+", execute " + jobName);
        }
    
        /**
         * 计算从当前时间currentDate开始,满足条件dayOfWeek, hourOfDay, 
         * minuteOfHour, secondOfMinite的最近时间
         * @return
         */
        public Calendar getEarliestDate(Calendar currentDate, int dayOfWeek,
                int hourOfDay, int minuteOfHour, int secondOfMinite) {
            //计算当前时间的WEEK_OF_YEAR,DAY_OF_WEEK, HOUR_OF_DAY, MINUTE,SECOND等各个字段值
            int currentWeekOfYear = currentDate.get(Calendar.WEEK_OF_YEAR);
            int currentDayOfWeek = currentDate.get(Calendar.DAY_OF_WEEK);
            int currentHour = currentDate.get(Calendar.HOUR_OF_DAY);
            int currentMinute = currentDate.get(Calendar.MINUTE);
            int currentSecond = currentDate.get(Calendar.SECOND);
    
            //如果输入条件中的dayOfWeek小于当前日期的dayOfWeek,则WEEK_OF_YEAR需要推迟一周
            boolean weekLater = false;
            if (dayOfWeek < currentDayOfWeek) {
                weekLater = true;
            } else if (dayOfWeek == currentDayOfWeek) {
                //当输入条件与当前日期的dayOfWeek相等时,如果输入条件中的
                //hourOfDay小于当前日期的
                //currentHour,则WEEK_OF_YEAR需要推迟一周   
                if (hourOfDay < currentHour) {
                    weekLater = true;
                } else if (hourOfDay == currentHour) {
                     //当输入条件与当前日期的dayOfWeek, hourOfDay相等时,
                     //如果输入条件中的minuteOfHour小于当前日期的
                    //currentMinute,则WEEK_OF_YEAR需要推迟一周
                    if (minuteOfHour < currentMinute) {
                        weekLater = true;
                    } else if (minuteOfHour == currentSecond) {
                         //当输入条件与当前日期的dayOfWeek, hourOfDay, 
                         //minuteOfHour相等时,如果输入条件中的
                        //secondOfMinite小于当前日期的currentSecond,
                        //则WEEK_OF_YEAR需要推迟一周
                        if (secondOfMinite < currentSecond) {
                            weekLater = true;
                        }
                    }
                }
            }
            if (weekLater) {
                //设置当前日期中的WEEK_OF_YEAR为当前周推迟一周
                currentDate.set(Calendar.WEEK_OF_YEAR, currentWeekOfYear + 1);
            }
            // 设置当前日期中的DAY_OF_WEEK,HOUR_OF_DAY,MINUTE,SECOND为输入条件中的值。
            currentDate.set(Calendar.DAY_OF_WEEK, dayOfWeek);
            currentDate.set(Calendar.HOUR_OF_DAY, hourOfDay);
            currentDate.set(Calendar.MINUTE, minuteOfHour);
            currentDate.set(Calendar.SECOND, secondOfMinite);
            return currentDate;
    
        }
    
        public static void main(String[] args) throws Exception {
    
            ScheduledExceutorTest2 test = new ScheduledExceutorTest2("job1");
            //获取当前时间
            Calendar currentDate = Calendar.getInstance();
            long currentDateLong = currentDate.getTime().getTime();
            System.out.println("Current Date = " + currentDate.getTime().toString());
            //计算满足条件的最近一次执行时间
            Calendar earliestDate = test
                    .getEarliestDate(currentDate, 3, 16, 38, 10);
            long earliestDateLong = earliestDate.getTime().getTime();
            System.out.println("Earliest Date = "
                    + earliestDate.getTime().toString());
            //计算从当前时间到最近一次执行时间的时间间隔
            long delay = earliestDateLong - currentDateLong;
            //计算执行周期为一星期
            long period = 7 * 24 * 60 * 60 * 1000;
            ScheduledExecutorService service = Executors.newScheduledThreadPool(10);
            //从现在开始delay毫秒之后,每隔一星期执行一次job1
            service.scheduleAtFixedRate(test, delay, period,
                    TimeUnit.MILLISECONDS);
    
        }
    }

    其核心在于根据当前时间推算出最近一个星期二 16:38:10 的绝对时间,然后计算与当前时间的时间差,作为调用 ScheduledExceutor 函数的参数。计算最近时间要用到 java.util.calendar 的功能。首先需要解释 Calendar 的一些设计思想。Calendar 有以下几种唯一标识一个日期的组合方式:

    • YEAR + MONTH + DAY_OF_MONTH
    • YEAR + MONTH + WEEK_OF_MONTH +
    • YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
    • YEAR+ DAY_OF_YEAR YEAR + DAY_OF_WEEK + WEEK_OF_YEAR

    上述组合分别加上 HOUR_OF_DAY + MINUTE + SECOND 即为一个完整的时间标识。本例采用了最后一种组合方式。输入为 DAY_OF_WEEK, HOUR_OF_DAY, MINUTE, SECOND 以及当前日期 , 输出为一个满足 DAY_OF_WEEK, HOUR_OF_DAY, MINUTE, SECOND 并且距离当前日期最近的未来日期。计算的原则是从输入的 DAY_OF_WEEK 开始比较,如果小于当前日期的 DAY_OF_WEEK,则需要向 WEEK_OF_YEAR 进一, 即将当前日期中的 WEEK_OF_YEAR 加一并覆盖旧值;如果等于当前的 DAY_OF_WEEK, 则继续比较 HOUR_OF_DAY;如果大于当前的 DAY_OF_WEEK,则直接调用 java.util.calenda 的 calendar.set(field, value) 函数将当前日期的 DAY_OF_WEEK, HOUR_OF_DAY, MINUTE, SECOND 赋值为输入值,依次类推,直到比较至 SECOND。也可以根据输入需求选择不同的组合方式来计算最近执行时间。

    4、Handler机制

    以上三种方式都是由Java语言提供的机制,其实Android 本身也提供了自己的机制,只不过需要我们灵活去应用,尤其是涉及到界面操作的周期性需要灵活控制的任务调度,Handler机制应该算是比较合适一种方式,结合其他机制可以无缝地操作界面。我以实现仿Windows 屏保机制来说明,简单说下需求,当设备在若干分钟无人进行交互的时候,自动播放屏保,这也可以看成一个灵活的任务调度,因为当到达指定时间之前,有人交互,此时又得重新计算起点,而不是固定的在一个时间间隔内一定会触发。

    public abstract class BaseActivity extends AppCompatActivity {
        public static final int MSG_WELCOME = 11;
        private final static long DELAY=10*60*1000;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            ActivityManager.addActivity(this);
            setFullScreen();
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            startTask();//首先在onResume 中开启任务调度,此时相当于开始倒计时,如果没被打断将会在DELAY 时间间隔之后执行预订的弹出屏保
        }
    
        @Override
        protected void onStop() {
            super.onStop();
            stopTask();//停止任务调度
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
        }
    
        private void setFullScreen(){
            requestWindowFeature(Window.FEATURE_NO_TITLE);
            getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                    WindowManager.LayoutParams.FLAG_FULLSCREEN);
        }
    
        @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
            stopTask();//当有人在交互的时候就中断当前的任务调度,重新开启
            startTask();
            return super.dispatchTouchEvent(ev);
        }
    
        private ObverHandler takePhotoHandler =new ObverHandler(this);
    
    
        protected void handleMsg(int what){
            if(what== MSG_WELCOME) {
                ScreenActivity.showScreenActivity(this);//当接收到Message 时,跳到屏保界面
                return;
            }
            return;
        }
    
        protected boolean isTopActivity(String activity) {
            android.app.ActivityManager am = (android.app.ActivityManager) getSystemService(ACTIVITY_SERVICE);
            ComponentName cn = am.getRunningTasks(1).get(0).topActivity;
            return cn.getClassName().contains(activity);
        }
    
        /**
        *开启周期性任务调度
        */
        protected void startTask(){
            if(takePhotoHandler !=null) {
                if(isTopActivity("ScreenActivity")){
                    return;
                }else{
                    takePhotoHandler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            takePhotoHandler.sendMsg(MSG_WELCOME);
                        }
                    }, DELAY);
                }
            }
        }
    
        /**
        *停止周期性任务调度,假如在还未到所指定的时间任务呗手动停止了,比如说有人交互了,此时需要重新计算任务开始的起点,所以需要在业务逻辑中手动去重新开启任务调度
        */
        private void stopTask(){
            if (takePhotoHandler !=null){
                LogUtil.showErroLog("STOP TASK WELCOMEActivity");
                takePhotoHandler.removeCallbacksAndMessages(null);//就是把未处理的Meesgae 全部清空
            }
        }
    
        static class ObverHandler extends Handler {
            private final WeakReference<BaseActivity> mAct;//声明弱引用
            //声明构造方法供外部调用构ObverHandler对象
            public ObverHandler(BaseActivity act){
                mAct=new WeakReference<>(act);
            }
            public void handleMessage(Message msg){
    
                mAct.get().handleMsg(msg.what);
            }
            public void sendMsg(int what){
                sendEmptyMessage(what);
            }
        }
    }
    

    以上屏保案例实质上借助了Handler的postDelayed方法和removeCallbacksAndMessages灵活实现的一种所谓的周期性任务调度,当然也可以借助其他机制来实现开启和停止,一切取决于你的需求。

    5、第三方开源库

    上述方法实现该任务调度比较麻烦,这就需要一个更加完善的任务调度框架来解决这些复杂的调度问题。幸运的是,开源工具包 Quartz 与 JCronTab 提供了这方面强大的支持(使用攻略参见IBM开发社区。)

    小结

    对于简单的基于起始时间点与时间间隔的任务调度,使用 Timer 就足够了;如果需要同时调度多个任务,基于线程池的 ScheduledTimer 是更为合适的选择;当任务调度的策略复杂到难以凭借起始时间点与时间间隔来描述时,Quartz 与 JCronTab 则体现出它们的优势。熟悉 Unix/Linux 的开发人员更倾向于 JCronTab,且 JCronTab 更适合与 Web 应用服务器相结合。Quartz 的 Trigger 与 Job 松耦合设计使其更适用于 Job 与 Trigger 的多对多应用场景。

    展开全文
  • 其主要提供了schedule,scheduleAtFixedRate,scheduleWithFixedDelay三个方法,分别用于延迟执行任务,特定频率周期性执行任务,特定延迟周期性执行任务。 public interface ScheduledExecutorS...

    概述

    • ScheduledExecutorService继承于ExecutorService,主要提供任务的延迟和周期性执行的功能。其主要提供了schedule,scheduleAtFixedRate,scheduleWithFixedDelay三个方法,分别用于延迟执行任务,以特定频率周期性执行任务,以特定延迟周期性执行任务。

      public interface ScheduledExecutorService extends ExecutorService {
      
          // 延迟delay时间执行
          public ScheduledFuture<?> schedule(Runnable command,
                                             long delay, TimeUnit unit);
          
          public <V> ScheduledFuture<V> schedule(Callable<V> callable,
                                                 long delay, TimeUnit unit);
          // 固定频率周期性执行
          public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                                        long initialDelay,
                                                        long period,
                                                        TimeUnit unit);
          // 固定延迟周期性执行
          public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                                                           long initialDelay,
                                                           long delay,
                                                           TimeUnit unit);
      
      }
      
    1. schedule:延迟delay时间执行一次;
    2. scheduleAtFixedRate:以给定的频率周期性执行,分别为initialDelay,initialDelay+period,initialDelay+2period,…,如果出现越界,如initialDelay+period时线程执行时间过长,超过了initialDelay+2period,则下一次从initialDelay+3*period开始执行,不会出现重叠问题,即遵循happen-before原则。如果线程池存在多个线程,则每次执行可能在不同的线程当中。周期性执行的command如果在执行期间抛了异常而没有捕获,则之后不会继续执行该command,即不会再周期性执行了,scheduleWithFixedDelay也是一样;
    3. scheduleWithFixedDelay:每次执行相隔delay时间,即第一次延迟initialDelay执行,执行完之后等待delay时间后执行第二次,依次类推,跟每次执行的时间无关。

    周期性任务停止执行的原因

    • scheduleAtFixedRate和scheduleWithFixedDelay在执行周期性任务过程当中,如果任务自身抛了异常而没有捕获,则会导致scheduleAtFixedRate和scheduleWithFixedDelay不会继续周期性执行该任务了,即该任务停止执行。实现原理如下:
    1. ScheduledThreadPoolExecutor内部定义了一个内部类ScheduledFutureTask,ScheduledFutureTask继承于FutureTask,由该内部类来对任务进行封装,提供周期性执行的功能。

      private class ScheduledFutureTask<V>
              extends FutureTask<V> implements RunnableScheduledFuture<V> {
              ...
      }
      
    2. ScheduledFutureTask的run方法实现如下:主要在runAndReset方法中执行该周期性任务,如果执行成功返回true,则调用setNextRunTime设置下次执行时间;如果该方法返回false,则不再调用setNextRunTime设置下次执行时间,故该周期性任务停止执行。

      public void run() {
          boolean periodic = isPeriodic();
          if (!canRunInCurrentRunState(periodic))
              cancel(false);
          else if (!periodic)
              ScheduledFutureTask.super.run();
          // 周期性任务执行,返回true则说明此次执行成功,
          // 则调用setNextRunTime设置下次执行时间,
          // 否则不再设置下次执行时间,故不再执行
          else if (ScheduledFutureTask.super.runAndReset()) {
              setNextRunTime();
              reExecutePeriodic(outerTask);
          }
      }
      
    3. runAndReset的实现:执行任务,在成功执行时,则ran为true,state的值还是NEW,故方法返回值为true。但是如果在执行过程中,即c.call()调用时,出现了异常,则ran设置为false,并在catch块中通过setExeception处理。在setException中将state更新为了EXCEPTIONAL,同时唤醒等待该任务结果的线程,则最终的ran && s == NEW为false,导致runAndReset方法返回false,由上面run的分析可知,该周期任务不再执行。

      protected boolean runAndReset() {
          if (state != NEW ||
              !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                           null, Thread.currentThread()))
              return false;
          boolean ran = false;
          int s = state;
          try {
              Callable<V> c = callable;
              if (c != null && s == NEW) {
                  try {
                      // 执行任务
                      c.call(); // don't set result
                      ran = true;
                  } catch (Throwable ex) {
                      setException(ex);
                  }
              }
          } finally {
              // runner must be non-null until state is settled to
              // prevent concurrent calls to run()
              runner = null;
              // state must be re-read after nulling runner to prevent
              // leaked interrupts
              
              // 重置任务状态,如果抛了异常,则
              // 在setException中已经将state更新为了EXCEPTIONAL
              s = state;
              if (s >= INTERRUPTING)
                  handlePossibleCancellationInterrupt(s);
          }
          return ran && s == NEW;
      }
      
    4. setException方法的定义如下:将state更新为EXCEPTIONAL,以便阻塞等待该任务执行结果的线程知道发生了异常,同时调用finishCompletion唤醒这些等待线程。

      /**
       * Causes this future to report an {@link ExecutionException}
       * with the given throwable as its cause, unless this future has
       * already been set or has been cancelled.
       *
       * <p>This method is invoked internally by the {@link #run} method
       * upon failure of the computation.
       *
       * @param t the cause of failure
       */
      protected void setException(Throwable t) {
          if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
              outcome = t;
              
              // 将state更新为EXCEPTIONAL
              UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
              
              // 唤醒阻塞等待该任务执行结果的线程
              finishCompletion();
          }
      }
      
    展开全文
  • Linux任务计划和周期性任务执行

    千次阅读 2018-06-08 08:22:19
    linux计划任务有两类at:未来某个时间点仅执行一次任务就结束的指令,at指令执行时必须要有atd这个服务支持。crontab:可以以时间单位为分钟,小时,每天,每周,每月,每年等循环执行某任务。单一任务at介绍:语法...
  • 2、周期性计划任务 一次性计划任务 在指定的日期、时间点自动的执行预先设置的一些命令操作,属于一次性计划任务 系统服务的名称:/etc/init.d/atd 设置格式:at [HH:MM] [yyyy-mm-dd] atq命令:查询当...
  • Java中周期性任务执行--Timer

    千次阅读 2011-09-08 10:09:16
    很多时候我们希望任务可以定时的周期性的执行,在最初的JAVA工具类库中,通过Timer可以实现定时的周期性的需求,但是有一定的缺陷,例如:Timer是基于绝对时间的而非支持相对时间,因此Timer对系统时钟比较敏感。...
  • 根据项目的进展,我们需要实现后台进行定时读取信息的功能,而最关键的实现部分是周期性功能,根据调研,决定使用whenever来实现这一功能。...whenever为周期性任务提供了哪些控制方式? 问题解决whenever周期
  • 1. Celery默认任务单元由任务生产者触发,但有时可能需要其自动触发,而Beat进程正是负责此类任务,能够自动触发定时/周期性任务. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ...
  • 在nova中可以通过添加@periodic_task.periodic_task 来产生一个周期任务。 例如使用默认周期任务: @periodic_task.periodic_task def _poll_rebooting_instances(self, context): if CONF.reboot_timeout > 0:...
  • Java提供的Time类可以周期性地或者延期执行任务,但是有时我们需要并行执行同样的任务,这个时候如果创建多个Time对象会给系统带来负担,解决办法是将定时任务放到线程池中执行。 Java的...
  • schedule(Callable callable, long delay, TimeUnit unit)  创建并执行在给定延迟后启用的 ScheduledFuture。 schedule(Runnable command, ... 创建并执行在给定延迟后启用的一次操作。
  • crontab主要作用: 比如我们每天需要清空日志记录文件,我们可以执行一段...'黑色星期五' 每到了周五就发作,计划任务和它一样的道理,只不过没有破坏,1、 计划任务,crontab命令选项: -u指定一个用户, -l列出...
  • 计算机系统有一系列的“周期”概念,区别、联系地理解这些概念至关重要。以下对时钟周期、振荡周期、机器周期、CPU周期、状态周期、指令周期、总线周期、任务周期...频率是描述周期性循环信号(包括脉冲信号)在单位时
  • 这篇文章主要介绍了python基于celery实现异步任务周期任务定时任务,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 hello, 小伙伴们, 好久不更新了,这一次带来...
  • 软件生命周期极各个周期任务

    千次阅读 2008-11-25 22:51:00
    软件生命周期由软件定义、软件开发和运行维护(也称为软件维护)3个时期组成,每个时期又进一步划分成若干个阶段。 软件定义时期的任务是: – 确定软件开发工程必须完成的总目标; – 确定工程的可行; – 导出实现...
  • 计算机系统有一系列的“周期”概念,区别、联系地理解这些概念至关重要。以下对时钟周期、振荡周期、机器周期、CPU周期、状态周期、指令周期、总线周期、任务周期进行简单介绍。...频率是描述周期性循环信号(包括
  • bpmn定义之camunda bpm生命周期

    万次阅读 2020-06-02 13:31:26
    eabpm对bpm的定义使用了过程自动化这个术语,我们在描述camunda bpm生命周期时也使用了这个术语。开发BPMN是为了更好地实现流程自动化。即使您不是it专家,您也需要理解流程自动化的含义,因为它将帮助您理解bpmn...
  • 软件生存周期各阶段的任务

    千次阅读 2017-06-06 10:06:15
    问题定义  这个阶段主要是确定“要解决的问题是什么”。通过对客户的访谈与调研,可以得出这个问题的答案,然后编写一份问题说明书或问题报告,文档应该包括问题定义、软件...可行研究  这个阶段主要是确
  • Ubuntu下周期执行任务-cron和crontab

    千次阅读 2018-06-23 12:04:05
    让系统每天去帮我们完成就比较轻松了,根据你自己的定义 可以定位到月 日 时 分 星期 ,以前有个很有名的病毒 '黑色星期五' 每到了周五就发作,计划任务和它一样的道理,只不过没有破坏, 1、 计划任务,crontab...
  • 软件生命周期每个阶段的基本任务

    千次阅读 2015-01-07 23:52:55
    软件生命周期每个阶段的基本任务 1、问题定义 2、可行分析 3、需求分析<软件定义时期,规格说明书> 4、总体设计 5、详细设计 6、编码和单元测试 7、综合测试<软件开发> 8、软件维护:改正维护、适应...
  • 软件生存周期各阶段活动定义浅释

    千次阅读 2012-09-25 10:18:56
    首先讲一下软件生存周期定义,即以需求为触发点,提出软件开发计划的那一刻开始直到软件在实际应用中完全报废为止可以认为是一个完整的软件生存周期,软件生存周期的提出是为了更好的管理、维护和升级软件。...
  • linux周期性执行程序命令crontab

    千次阅读 2015-07-08 17:38:14
    前一天学习了 at 命令是针对仅运行一次的任务,循环运行的例行计划任务,linux系统则是由 cron (crond) 这个系统服务来控制的。Linux 系统上面原本就有非常多的计划工作,因此这个系统服务是默认启动的。...
  • 软件工程生命周期各个阶段完成的任务

    万次阅读 多人点赞 2018-09-23 21:10:35
    软件生命周期各个阶段分别是 问题定义 可行行研究 需求分析 总体设计(概要设计) 详细设计 编码与单元测试 综合测试 维护 (一)问题定义 关键任务:“要解决的问题是什么” 问题定义报告(文档):通过...
  • ScheduledThreadPoolExecutor 在进一步了解ScheduledThreadPoolExecutor类之前,先学习下...类图显示,该类实现Runnable接口并继承FutureTask类,表明该类是一个被包装的任务,同时该类实现Delayed接口和Comparable&...
  • 周期性学习率(Cyclical Learning Rate)技术

    千次阅读 多人点赞 2018-12-04 09:36:02
    本文介绍神经网络训练中的周期性学习率技术。 Introduction 学习率(learning_rate, LR)是神经网络训练过程中最重要的超参数之一,它对于快速、高效地训练神经网络至关重要。简单来说,LR决定了我们当前的权重参数...
  • Qt使用QTimer实现函数的周期性执行

    千次阅读 2017-08-31 11:23:56
    要求:已经定义了一个函数,要求他每隔1秒,自动执行一次。 实现方法:将需要执行的函数定义为槽函数。使用QTimer计时。定时1000ms,将timeout信号连接到需要执行的槽函数上。 1.使用QTimer的要求: Header: #...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 218,310
精华内容 87,324
关键字:

周期性任务定义