亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java項目中怎么對任務進行調度

發布時間:2020-12-02 15:17:08 來源:億速云 閱讀:165 作者:Leah 欄目:編程語言

這期內容當中小編將會給大家帶來有關Java項目中怎么對任務進行調度,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

簡介: 綜觀目前的 Web 應用,多數應用都具備任務調度的功能。本文由淺入深介紹了幾種任務調度的 Java 實現方法,包括 Timer,Scheduler, Quartz 以及 JCron Tab,并對其優缺點進行比較,目的在于給需要開發任務調度的程序員提供有價值的參考。

任務調度是指基于給定時間點,給定時間間隔或者給定執行次數自動執行任務。這里由淺入深介紹四種任務調度的 Java 實現:

Timer
ScheduledExecutor
開源工具包 Quartz
開源工具包 JCronTab

此外,為結合實現復雜的任務調度,本文還將介紹 Calendar 的一些使用方法。

Timer

相信大家都已經非常熟悉 java.util.Timer 了,它是最簡單的一種實現任務調度的方法,下面給出一個具體的例子:

package com.ibm.scheduler;
import java.util.Timer;
import java.util.TimerTask;
public class TimerTest extends TimerTask {
 private String jobName = "";
 public TimerTest(String jobName) {
 super();
 this.jobName = jobName;
 }
 @Override
 public void run() {
 System.out.println("execute " + jobName);
 }
 public static void main(String[] args) {
 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);
 }
}

Output:

execute job1
execute job1
execute job2
execute job1
execute job1
execute job2

使用 Timer 實現任務調度的核心類是 Timer 和 TimerTask。其中 Timer 負責設定 TimerTask 的起始與間隔執行時間。使用者只需要創建一個 TimerTask 的繼承類,實現自己的 run 方法,然后將其丟給 Timer 去執行即可。

Timer 的設計核心是一個 TaskList 和一個 TaskThread。Timer 將接收到的任務丟到自己的 TaskList 中,TaskList 按照 Task 的最初執行時間進行排序。TimerThread 在創建 Timer 時會啟動成為一個守護線程。這個線程會輪詢所有任務,找到一個最近要執行的任務,然后休眠,當到達最近要執行任務的開始時間點,TimerThread 被喚醒并執行該任務。之后 TimerThread 更新最近一個要執行的任務,繼續休眠。

Timer 的優點在于簡單易用,但由于所有任務都是由同一個線程來調度,因此所有任務都是串行執行的,同一時間只能有一個任務在執行,前一個任務的延遲或異常都將會影響到之后的任務。

ScheduledExecutor

鑒于 Timer 的上述缺陷,Java 5 推出了基于線程池設計的 ScheduledExecutor。其設計思想是,每一個被調度的任務都會由線程池中一個線程去執行,因此任務是并發執行的,相互之間不會受到干擾。需要注意的是,只有當任務的執行時間到來時,ScheduedExecutor 才會真正啟動一個線程,其余時間 ScheduledExecutor 都是在輪詢任務的狀態。

package com.ibm.scheduler;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ScheduledExecutorTest implements Runnable {
    private String jobName = "";
    public ScheduledExecutorTest(String jobName) {
        super();
        this.jobName = jobName;
    }
    @Override
    public void run() {
        System.out.println("execute " + jobName);
    }
    public static void main(String[] args) {
        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);
    }
}

Output:

execute job2
execute job1
execute job2
execute job1
execute job2
execute job1

清單 2 展示了 ScheduledExecutorService 中兩種最常用的調度方法 ScheduleAtFixedRate 和 ScheduleWithFixedDelay。ScheduleAtFixedRate 每次執行時間為上一次任務開始起向后推一個時間間隔,即每次執行時間為 :initialDelay, initialDelay+period, initialDelay+2*period, …;ScheduleWithFixedDelay 每次執行時間為上一次任務結束起向后推一個時間間隔,即每次執行時間為:initialDelay, initialDelay+executeTime+delay, initialDelay+2*executeTime+2*delay。由此可見,ScheduleAtFixedRate 是基于固定時間間隔進行任務調度,ScheduleWithFixedDelay 取決于每次任務執行的時間長短,是基于不固定時間間隔進行任務調度。

Timer 和 ScheduledExecutor 都僅能提供基于開始時間與重復間隔的任務調度,不能勝任更加復雜的調度需求。比如,設置每星期二的 16:38:10 執行任務。該功能使用 Timer 和 ScheduledExecutor 都不能直接實現,但我們可以借助 Calendar 間接實現該功能。

package com.ibm.scheduler;
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);
    }
}

Output:

Current Date = Wed Feb 02 17:32:01 CST 2011
Earliest Date = Tue Feb 8 16:38:10 CST 2011
Date = Tue Feb 8 16:38:10 CST 2011, execute job1
Date = Tue Feb 15 16:38:10 CST 2011, execute job1

清單 3 實現了每星期二 16:38:10 調度任務的功能。其核心在于根據當前時間推算出最近一個星期二 16:38:10 的絕對時間,然后計算與當前時間的時間差,作為調用 ScheduledExceutor 函數的參數。計算最近時間要用到 java.util.calendar 的功能。首先需要解釋 calendar 的一些設計思想。Calendar 有以下幾種唯一標識一個日期的組合方式:

 YEAR + MONTH + DAY_OF_MONTH
 YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
 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。讀者可以根據輸入需求選擇不同的組合方式來計算最近執行時間。

可以看出,用上述方法實現該任務調度比較麻煩,這就需要一個更加完善的任務調度框架來解決這些復雜的調度問題。幸運的是,開源工具包 Quartz 與 JCronTab 提供了這方面強大的支持。

Quartz 可以滿足更多更復雜的調度需求,首先讓我們看看如何用 Quartz 實現每星期二 16:38 的調度安排:

package com.ibm.scheduler;
import java.util.Date;
import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.Trigger;
import org.quartz.helpers.TriggerUtils;
public class QuartzTest implements Job {
    @Override
    //該方法實現需要執行的任務
    public void execute(JobExecutionContext arg0) throws JobExecutionException {
        System.out.println("Generating report - "
                + arg0.getJobDetail().getFullName() + ", type ="
                + arg0.getJobDetail().getJobDataMap().get("type"));
        System.out.println(new Date().toString());
    }
    public static void main(String[] args) {
        try {
            // 創建一個Scheduler
            SchedulerFactory schedFact =
            new org.quartz.impl.StdSchedulerFactory();
            Scheduler sched = schedFact.getScheduler();
            sched.start();
            // 創建一個JobDetail,指明name,groupname,以及具體的Job類名,
            //該Job負責定義需要執行任務
            JobDetail jobDetail = new JobDetail("myJob", "myJobGroup",
                    QuartzTest.class);
            jobDetail.getJobDataMap().put("type", "FULL");
      // 創建一個每周觸發的Trigger,指明星期幾幾點幾分執行
            Trigger trigger = TriggerUtils.makeWeeklyTrigger(3, 16, 38);
            trigger.setGroup("myTriggerGroup");
            // 從當前時間的下一秒開始執行
            trigger.setStartTime(TriggerUtils.getEvenSecondDate(new Date()));
            // 指明trigger的name
            trigger.setName("myTrigger");
            // 用scheduler將JobDetail與Trigger關聯在一起,開始調度任務
            sched.scheduleJob(jobDetail, trigger);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Output:

Generating report - myJobGroup.myJob, type =FULL
Tue Feb 8 16:38:00 CST 2011
Generating report - myJobGroup.myJob, type =FULL
Tue Feb 15 16:38:00 CST 2011

清單 4 非常簡潔地實現了一個上述復雜的任務調度。Quartz 設計的核心類包括 Scheduler, Job 以及 Trigger。其中,Job 負責定義需要執行的任務,Trigger 負責設置調度策略,Scheduler 將二者組裝在一起,并觸發任務開始執行。

上述就是小編為大家分享的Java項目中怎么對任務進行調度了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

沙河市| 鄂州市| 任丘市| 抚宁县| 米脂县| 荥经县| 额尔古纳市| 沂源县| 澳门| 罗田县| 柏乡县| 南靖县| 千阳县| 利辛县| 海晏县| 武安市| 沾化县| 项城市| 宜宾市| 桃源县| 文登市| 永嘉县| 溧阳市| 杨浦区| 新巴尔虎右旗| 红河县| 东方市| 得荣县| 色达县| 丰城市| 准格尔旗| 迭部县| 九龙坡区| 利辛县| 贞丰县| 璧山县| 磐石市| 合川市| 墨江| 屯昌县| 临朐县|