zoukankan      html  css  js  c++  java
  • java 任务调度实现的总结

    Timer

    Timer的核心是Timer和TimerTask,Timer负责设定TimerTask的起始与间隔执行时间,使用者需要建立一个timeTask的继承类,实现run方法,然后将其交给Timer使用即可。

    Timer的设计是一个TaskList和一个TaskThread。Timer将接到的任务交给TaskList中,TaskList按照最初执行时间进行排序。TimerThread在创建Timer会成为一个守护线程。这个线程会轮询任务,找到一个最近要执行的任务,然后休眠,当到达最近要执行任务的开始时间点,TimerThread被唤醒并执行任务。之后Timer更新最近要执行的任务,继续休眠。

    缺点:所有任务都是串行的,前一个任务的延迟或异常会影响到后面的任务。

    demo:

    1 Timer timer = new Timer();
    2 TimeTask task = new TimeTask(){
    3         public void run(){
    4          //具体业务        
    5     }
    6 };
    7 timer.scheduleAtFixedRate(task, new Date(), 1* 30 * 1000l);

    ScheduledExecutor

    java 5退出了ScheduledExecutor框架, 与timer不同的是,任务执行时是并发的,相互之间不受干扰,(保留意见,不一定非得是并发执行的就好),只有当任务执行时间到的时候,scheduedExecutor才会真正的执行线程,其余时间ScheduledExecutor都在轮询任务的状态。

     1 public class ScleduledExecutorTest implements Runnable{
     2   private String jobName = "";
     3   public ScheduledExecutorTest(String jobName){
     4   super();
     5    this.jobName = jobName;    
     6   }  
     7    public void run(){
     8      System.out.println("execute " + jobName);
     9    }   
    10    public static void main(String[] args){
    11    ScheduledExecutorService service = Executors.newScheduledThreadPool(10);
    12    service.scheduleAtFixRate(new ScheduledExecutorTest("job1"),1,1,TimeUnit.SECONDS); 
    13 service.scheduleWithFixedDelay(
    14                 new ScheduledExecutorTest("job2"), 1,
    15                 1, TimeUnit.SECONDS);
    16    }
    17 }

    注意,能做定时执行的只能是newScheduledThreadPool 这个是专门做调度任务的,其他的线程池特性如下:

    newSingleThreadExecutor:创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。

    newFixedThreadPool:创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。

    newCachedThreadPool:创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。

    newScheduledThreadPool:创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。

    newSingleThreadExecutor:创建一个单线程的线程池。此线程池支持定时以及周期性执行任务的需求。

    并且线程池在停止的时候所用的shutdown与shutdownNow是不一样的,shutdown会继续执行并且完成所有未执行的任务,shutdownNow 会清楚所有未执行的任务并且在运行线程上调用interrupt() 。然而interrupt仅仅是在当前线程中打一个停止的标记。还需要加一个判断才能对线程的停止。

    Thread.java提供了两个方法:

    this.interrupted();

    this.isInterrupted();

    官方帮助文档对interrupted方法的解释是:

    调用后,线程的中断状态被清除,也就是如果线程中断了,第一次返回true,第二次返回false。 并且这是一个静态方法。

    isInterrupted不是一个静态方法,也不会清除中断状态。

    中断线程通过标记判断,要么抛出异常,要么直接return。

     

    ScheduledExecutor可以与Calendar实现更复杂的调度,比如制定每周的某个时间段执行。

    也就是在执行线程中加上了Calandar的判断

    Calendar ca = Calendar.getInstance();
            int h = ca.get(Calendar.HOUR_OF_DAY);
            int mi = h*60+ca.get(Calendar.MINUTE);
            int ss = ca.get(Calendar.SECOND);

    通过if进行判断,要注意,调度器的唤醒时间最好是各个线程激活的最大公约数。

    Quartz

    需要更精准的调度,需要使用Quartz框架了。

    public static void main(String args[]){
       UpdateJob.task(AutoJob.class,"0/1 * * * * ?" );
    }
    public class UpdateClientTimer {
    
        public static void task(Class cls, String expression) throws SchedulerException {
    
            SchedulerFactory schedulerFactory = new StdSchedulerFactory();
            Scheduler scheduler = schedulerFactory.getScheduler();
            long ctime = System.currentTimeMillis();
            JobDetail jobDetail = new JobDetail("detail", "group", cls);
            CronTrigger cronTrigger = new CronTrigger("cronTrigger", "group");
            try {
                CronExpression cexp = new CronExpression(expression);
                cronTrigger.setCronExpression(cexp);
            } catch (Exception e) {
                e.printStackTrace();
            }
            scheduler.scheduleJob(jobDetail, cronTrigger);
            scheduler.start();
        }
    }
    调度周期是 "0/1 * * * * ?" 更精准的调度需要自行配置。
    UpdateClientTimer 大体与官方文档相当。真正执行业务在本例的Autojob中。
    public class AutoJob implements Job {
        public void execute(JobExecutionContext arg0) throws JobExecutionException {
            Calendar ca = Calendar.getInstance();
            int h = ca.get(Calendar.HOUR_OF_DAY);
            int mi = h*60+ca.get(Calendar.MINUTE);
            int ss = ca.get(Calendar.SECOND);
            
            if(过滤条件){
        
            }
    
    }

    Quartz的核心类包括Scheduler,job以及Trigger。其中job负责定义需要执行的任务,trigger负责设置调度策略,Scheduler 将二者组装在一起。

    有相关的官方说明文档,可以直接拿demo用。

     



  • 相关阅读:
    [转载]注解
    Spring可扩展的XML Schema机制 NamespaceHandlerSupport
    jvm中的年轻代 老年代 持久代 gc ----------转载
    反射原理
    舍入误差
    mysql突然宕机后事务如何处理?
    redis为什么设计成单线程并且还这么快?
    mysql架构学习
    用户级线程和内核级线程的区别
    G1垃圾收集器
  • 原文地址:https://www.cnblogs.com/caobojia/p/6344628.html
Copyright © 2011-2022 走看看