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用。

 

 

 

 



 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM