日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

4.定時(shí)調(diào)度類Timer和TimerTask

 印度阿三17 2020-03-10

一.概述

  • 在日常開發(fā)中我們經(jīng)常執(zhí)行定時(shí)任務(wù),此時(shí)我們可以使用守護(hù)線程或者是Timer類,此處我們避免守護(hù)線程使用的繁瑣就使用Timer類

1.Timer類和TimerTask類

  • 在java.util包下

  • Timer類:實(shí)現(xiàn)線程任務(wù)調(diào)度

    • ?void schedule(TimerTask task, long delay, long period) ?:在指定的延遲之后開始 ,重新執(zhí)行固定延遲執(zhí)行的指定任務(wù)。

    • ?void schedule(TimerTask task, long delay) ?:在指定的延遲之后安排指定的任務(wù)執(zhí)行。?

  • TimerTask類:實(shí)現(xiàn)定時(shí)處理任務(wù)的接口,我們需要實(shí)現(xiàn)此接口來完成定時(shí)任務(wù)

?轉(zhuǎn)載:https://www.cnblogs.com/xsjzhao/p/10651704.html

1 關(guān)于 (時(shí)間寶貴的請(qǐng)?zhí)^)

  • 什么是定時(shí)任務(wù)調(diào)度
    基于給定的時(shí)間點(diǎn),給定的時(shí)間間隔或者給定的執(zhí)行次數(shù)自動(dòng)執(zhí)行的任務(wù)。
  • 在Java中的定時(shí)調(diào)度工具
    • Timer
    • Quartz
  • 兩者主要區(qū)別
    1. 出身上,Timer是Java提供的原生Scheduler(任務(wù)調(diào)度)工具類,不需要導(dǎo)入其他jar包;而Quartz是OpenSymphony開源組織在任務(wù)調(diào)度領(lǐng)域的一個(gè)開源項(xiàng)目,完全基于Java實(shí)現(xiàn)。
    2. 功能上,如需要實(shí)現(xiàn)在某個(gè)具體時(shí)間執(zhí)行什么任務(wù)的話,Timer足以勝任;如需要實(shí)現(xiàn)每個(gè)星期六8點(diǎn)鬧鐘提醒之類的復(fù)雜任務(wù),就需要用Quartz。因此,Quartz在時(shí)間控制上的功能遠(yuǎn)比Timer強(qiáng)大和完善。
    3. 底層上,Timer使用一個(gè)后臺(tái)線程去執(zhí)行定時(shí)任務(wù),Quartz擁有后臺(tái)線程執(zhí)行池(類比JDBC連接池),能夠使用多個(gè)執(zhí)行線程去執(zhí)行定時(shí)任務(wù)。

簡而言之,Quartz > Timer,Timer是被動(dòng)地根據(jù)既定時(shí)間去調(diào)度任務(wù)的,Quartz則是自己主動(dòng)定制時(shí)間規(guī)則去支持更加豐富地調(diào)度方法。
本文主要是講解Timer工具類的,故而下文中不會(huì)過多討論Quartz。

  • 前導(dǎo)知識(shí)
Timer, Quartz的使用Quartz, Spring的整合
Java編程知識(shí) Spring基礎(chǔ)知識(shí)

2 Timer簡介和配套視頻課程

Timer類位于java.util包下,有關(guān)Timer類的詳細(xì)描述信息請(qǐng)點(diǎn)擊這里訪問Oracle Java的官方api文檔查閱。

Timer工具類圖是Timer工具類及有關(guān)類的類圖。
Timer工具類圖

快速開始:

/*
 * Foo.java -- JDK 1.8
 */

package timer;

import java.util.Timer;
import java.util.TimerTask;

/**
 * Description:
 * <p>
 * <p>
 * @author ascribed
 * @date 2019-04-03 Wed PM 19:15:08
 */

public class Foo {  
    public static void main(String[] args) {
        Timer timer = new Timer(); // 1. 創(chuàng)建Timer實(shí)例,關(guān)聯(lián)線程不能是daemon(守護(hù)/后臺(tái))線程
        FooTimerTask fooTimerTask = new FooTimerTask(); // 2. 創(chuàng)建任務(wù)對(duì)象
        timer.schedule(fooTimerTask, 3000L, 2000L); // 3. 通過Timer定時(shí)定頻率調(diào)用fooTimerTask的業(yè)務(wù)代碼
    }
}

class FooTimerTask extends TimerTask {
    @Override
    public void run() {
        // TODO 業(yè)務(wù)代碼......
        System.out.println("Hello Timer!");
    }
}

3 Timer函數(shù)和綜合運(yùn)用

3.1 Timer定時(shí)函數(shù)的用法

注意:Timer類在時(shí)間granularity(粒度)是毫秒級(jí)的,實(shí)際上Timer的schedule系列方法獲取時(shí)間的方式是System.currentTimeMillis()(當(dāng)前時(shí)間與Unix元年之差,類型為long),最多只能到毫秒級(jí),而一些操作系統(tǒng)的計(jì)時(shí)精度會(huì)達(dá)到1/10毫秒。

3.1.1 schedule()方法的4種用法

  1. schedule(TimerTask task, Date time)
    作用
    在時(shí)間等于或超過time的時(shí)候執(zhí)行且僅執(zhí)行一次task (單次)。
    源碼
    public void schedule(TimerTask task, Date time) {
        sched(task, time.getTime(), 0);
    }
  1. schedule(TimerTask task, Date firstTime, long period)
    作用
    時(shí)間等于或超過firstTime時(shí)首次執(zhí)行task,之后每隔peroid毫秒重復(fù)執(zhí)行一次task (多次)。
    源碼
    public void schedule(TimerTask task, long delay, long period) {
        if (delay < 0)
            throw new IllegalArgumentException("Negative delay.");
        if (period <= 0)
            throw new IllegalArgumentException("Non-positive period.");
        sched(task, System.currentTimeMillis() delay, -period);
    }
  1. schedule(TimerTask task, long delay)
    作用
    等待delay毫秒后執(zhí)行且僅執(zhí)行一次task (單次)。
    源碼
    public void schedule(TimerTask task, long delay) {
        if (delay < 0)
            throw new IllegalArgumentException("Negative delay.");
        sched(task, System.currentTimeMillis() delay, 0);
    }
  1. schedule(TimerTask task, long delay, long period)
    作用
    等待delay毫秒后首次執(zhí)行task, 之后每個(gè)period毫秒重復(fù)執(zhí)行一次task (多次)。
    源碼
    public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
        if (delay < 0)
            throw new IllegalArgumentException("Negative delay.");
        if (period <= 0)
            throw new IllegalArgumentException("Non-positive period.");
        sched(task, System.currentTimeMillis() delay, period);
    }

3.1.2 scheduleAfixRate()的2種用法

  1. scheduleAtFixedRate(TimerTask task, Date firstTime, long period)
    作用
    時(shí)間等于或超過time時(shí)首次執(zhí)行task,之后每隔peroid毫秒重復(fù)執(zhí)行一次task (多次, 同schedule第2種用法)。
    源碼
    public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
        if (delay < 0)
            throw new IllegalArgumentException("Negative delay.");
        if (period <= 0)
            throw new IllegalArgumentException("Non-positive period.");
        sched(task, System.currentTimeMillis() delay, period);
    }
  1. scheduleAtFixedRate(TimerTask task, long delay, long period)
    作用
    等待delay毫秒后首次執(zhí)行task, 之后每個(gè)period毫秒重復(fù)執(zhí)行一次task (多次, 同schedule第4種用法)。
    源碼
    public void scheduleAtFixedRate(TimerTask task, Date firstTime, long period) {
        if (period <= 0)
            throw new IllegalArgumentException("Non-positive period.");
        sched(task, firstTime.getTime(), period);
    }

筆記:

  1. schedule()和scheduleAtFixedRate()方法都能實(shí)現(xiàn)對(duì)任務(wù)的一次或多次調(diào)度。
  2. schedule()按是否可重復(fù)執(zhí)行分為單次和多次,按任務(wù)初次執(zhí)行計(jì)算方式分為delay(long型延遲毫秒數(shù))和time(Date型時(shí)間)。
  3. schedule()和scheduleAtFixedRate()最終都是調(diào)用Timer類下的sched()方法實(shí)現(xiàn)的。
    演示代碼包含DemoTimer.java和TimerUtils.java,代碼清單:
/*
 * DemoTimer.java -- JDK 1.8
 */

package timer;

import java.util.Calendar;
import java.util.Timer;
import java.util.TimerTask;

/**
 * Description:
 * <p>
 * <p>
 * @author ascribed
 * @date 2019-04-03 Wed PM 18:37:03
 */

public class DemoTimer {
    public static void main(String[] args) {
        Calendar calendar = TimerUtils.current();
        TimerUtils.miscellaneous("Current time is : ", calendar.getTime());
        calendar.add(Calendar.SECOND, 3); // 當(dāng)前時(shí)間加3秒

        Timer timer = new Timer(); 
        DemoTimerTask demoTimerTask = new DemoTimerTask("No. 1"); 
        
        demoTimerTask.setName("schedule1"); 
        timer.schedule(demoTimerTask, calendar.getTime()); // 3.1.1.1
        
//        demoTimerTask.setName("schedule2");
//        timer.schedule(demoTimerTask, calendar.getTime(), 2000); // 3.1.1.2
//        
//        demoTimerTask.setName("schedule3");
//        timer.schedule(demoTimerTask, 3000); // 3.1.1.3
//        
//        demoTimerTask.setName("schedule4");
//        timer.schedule(demoTimerTask, 3000, 2000); // 3.1.1.4
//        
//        demoTimerTask.setName("scheduleAtFixedRate1");
//        timer.scheduleAtFixedRate(demoTimerTask, calendar.getTime(), 2000); // 3.1.2.1
//        
//        demoTimerTask.setName("scheduleAtFixedRate2"); 
//        timer.scheduleAtFixedRate(demoTimerTask, 3000, 2000); // 3.1.2.2
    }
}

class DemoTimerTask extends TimerTask {

    String name; // 任務(wù)名

    public DemoTimerTask(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        TimerUtils.miscellaneous("Current time is : ", TimerUtils.current().getTime());
        System.out.println("Current exec name is : "   name); // 打印當(dāng)前name的內(nèi)容
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

/*
 * TimerUtils.java -- JDK 1.8
 */

package timer;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimerTask;

/**
 * Description:
 * <p>
 * <p>
 * @author ascribed
 * @date 2019-04-03 Wed PM 18:40:26
 */

public class TimerUtils {
    final static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 定義日期格式
    static Calendar current() {
        Calendar calendar = Calendar.getInstance(); // 通過靜態(tài)工廠方法創(chuàng)建Calendar實(shí)例
        return calendar;
    }
    static void schedtime(TimerTask task) {
        System.out.println("scheduled time is "   sdf.format(task.scheduledExecutionTime()));
    }
    
    static void miscellaneous(String str, Date date) {
        System.out.println(str   sdf.format(date));
    }
}

3.2 其他重要函數(shù)

3.2.1 TimerTask的cancel(), scheduledExecutionTime()

  1. cancel()
    作用
    終止此計(jì)時(shí)器,丟棄所有當(dāng)前已安排(scheduled)的任務(wù)。
    說明
    通過查看源碼,TimerTask的實(shí)現(xiàn)機(jī)制是通過設(shè)置標(biāo)志位來記錄timer task的狀態(tài),調(diào)用cancel()方法的timer task實(shí)例并沒有從相應(yīng)TaskQueue隊(duì)列移除,這是和Timer類的cancel()方法不同之處。
    源碼
    public boolean cancel() {
        synchronized(lock) {
            boolean result = (state == SCHEDULED);
            state = CANCELLED;
            return result;
        }
    }
    
  1. scheduledExecutionTime()
    作用
    從此計(jì)時(shí)器的任務(wù)隊(duì)列中移除所有已取消(canceled)的任務(wù)。
    返回值
    從隊(duì)列中移除的任務(wù)數(shù)。
    源碼
    public long scheduledExecutionTime() {
        synchronized(lock) {
            return (period < 0 ? nextExecutionTime   period
                               : nextExecutionTime - period);
        }
    }

不能與fixed-delay執(zhí)行式的重復(fù)任務(wù)搭配使用,也就是不用于schedule方法,應(yīng)為schedule方法的(scheduled execution time)計(jì)劃執(zhí)行時(shí)間會(huì)偏移理想的計(jì)劃時(shí)間,對(duì)她使用這個(gè)方法沒有無意義。
演示代碼清單:

/*
 * CancelTest.java -- JDK 1.8
 */

package timer;

import java.util.Timer;
import java.util.TimerTask;

/**
 * Description:
 * <p>
 * <p>
 * @author ascribed
 * @date 2019-04-03 Wed PM 19:43:04
 */

public class CancelTest {
    public static void main(String[] args) {
        Timer timer = new Timer();
        MyTimerTask myTimerTask = new MyTimerTask("schedule");
        TimerUtils.miscellaneous("Current time is : ", TimerUtils.current().getTime());
        timer.schedule(myTimerTask, 3000, 2000); // 3.2.1
//        timer.schedule(myTimerTask, 3000); // 3.3.2
//        TimerUtils.schedtime(myTimerTask);
    }
}
class MyTimerTask extends TimerTask {
    private String name;
    private Integer count = 0;
    
    public MyTimerTask(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        if (count < 3) {
            TimerUtils.miscellaneous("Current time is : ", TimerUtils.current().getTime());
            System.out.println("Current exec name is : "   name);
            count  ;
        } else {
            cancel();
            System.out.println("Task canceled");
            System.exit(0);
        }
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

3.2.2 Timer的cancel(), purge()

  1. cancel()
    作用
    終止此計(jì)時(shí)器,丟棄所有當(dāng)前已安排的任務(wù)。
    源碼
    public void cancel() {
        synchronized(queue) {
            thread.newTasksMayBeScheduled = false;
            queue.clear();
            queue.notify();  // 防止隊(duì)列已為空的處理
        }
    }
  1. purge()
    作用
    purge,意為凈化;(將不需要的東西)從......清除,相比消滅顯得優(yōu)雅一些。從此計(jì)時(shí)器的任務(wù)隊(duì)列中移除所有已取消的任務(wù)。
    返回值
    從隊(duì)列中移除的任務(wù)數(shù)。
    源碼
     public int purge() {
         int result = 0;

         synchronized(queue) {
             for (int i = queue.size(); i > 0; i--) {
                 if (queue.get(i).state == TimerTask.CANCELLED) {
                     queue.quickRemove(i);
                     result  ;
                 }
             }

             if (result != 0)
                 queue.heapify();
         }

         return result;
     }
}

演示代碼:

/*
 * CancelTest.java -- JDK 1.8
 */

package timer;

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

/**
 * Description:
 * <p>
 * <p>
 * @author ascribed
 * @date 2019-04-03 Wed PM 19:43:04
 */

public class CancelTest {
    public static void main(String[] args) throws InterruptedException {
        Timer timer = new Timer();
        MyTimerTask task1 = new MyTimerTask("task1");
        MyTimerTask task2 = new MyTimerTask("task2");
        TimerUtils.miscellaneous("start time is : ", new Date());
        // task1首次執(zhí)行是距離現(xiàn)在時(shí)間2秒后,之后每隔2秒執(zhí)行一次
        // task2首次執(zhí)行是距離現(xiàn)在時(shí)間1秒后,之后每隔2秒執(zhí)行一次
        timer.schedule(task1, 1000, 2000); // 奇數(shù)次執(zhí)行
        timer.schedule(task2, 2000, 2000); // 偶數(shù)次執(zhí)行
//        System.out.println("current canceled task number is : "   timer.purge());
        Thread.sleep(5000); // 當(dāng)前線程休眠5秒后cancel生效,沒有此句立即觸發(fā)cancel
        TimerUtils.miscellaneous("cancel time is : ", new Date());
        /*3.2.2.1
        下面兩句執(zhí)行完后程序只剩下后臺(tái)線程,JRE判定當(dāng)前程序結(jié)束
        因?yàn)楫?dāng)前程序只有后臺(tái)線程,所有前臺(tái)線程結(jié)束,后臺(tái)的工作無前臺(tái)線程使用就是沒有意義的
         */
        timer.cancel(); // 當(dāng)前線程若檢測(cè)到timer對(duì)隊(duì)列中的任務(wù)進(jìn)行調(diào)度則終止timer并從任務(wù)隊(duì)列移除所有任務(wù)
        System.out.println("Tasks all canceled!"); // 若此句輸出后看到還有任務(wù)運(yùn)行則停止所有運(yùn)行的程序,這可能是之前運(yùn)行的程序未終止
        // 3.2.2.2
//        task1.cancel(); // 當(dāng)前線程每次檢測(cè)到timer對(duì)task1進(jìn)行schedule取消task1
//        System.out.println("current canceled task number is : "   timer.purge());
    }
}

class MyTimerTask extends TimerTask {
    private String name;
    private Integer count = 0;

    public MyTimerTask(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        if (count < 3) {
            TimerUtils.miscellaneous("Current time is : ", TimerUtils.current()
                    .getTime());
            System.out.println("Current exec name is : "   name);
            count  ;
        } else {
            cancel();
            System.out.println("Task canceled");
            System.exit(0);
        }
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

3.3 schedule()和scheduledAtFixedRate()的區(qū)別

兩種情況看區(qū)別一覽表

方法schedulescheduleAtFixedRate
首次計(jì)劃執(zhí)行時(shí)間早于當(dāng)前時(shí)間 "fixed-delay",用代碼的形式理解就是scheduleAtfixedDelay();如果第一次執(zhí)行時(shí)間被delay了,隨后的執(zhí)行時(shí)間按照上一次實(shí)際執(zhí)行完成的時(shí)間點(diǎn)進(jìn)行計(jì)算。 "fixed-rate",義如其名;如果第一次執(zhí)行時(shí)間按照上一次開始的時(shí)間點(diǎn)進(jìn)行計(jì)算,并且為了趕上進(jìn)度會(huì)多次執(zhí)行任務(wù),因此TimerTask中的執(zhí)行體需要考慮同步
任務(wù)執(zhí)行所需的時(shí)間超出任務(wù)的執(zhí)行周期間隔 下一次執(zhí)行時(shí)間相對(duì)于上一次實(shí)際執(zhí)行完成的時(shí)間點(diǎn),因此執(zhí)行時(shí)間會(huì)不斷延后。 下一次執(zhí)行時(shí)間相對(duì)于上一次開始的時(shí)間點(diǎn),因此執(zhí)行時(shí)間一般不會(huì)延后,因此存在并發(fā)性。

fixed-delay和fixed-rate執(zhí)行的區(qū)別

  1. 對(duì)于fixed-delay執(zhí)行講解:
    如當(dāng)前時(shí)間2020-01-01 00:01:00,period為2000毫秒,將開始執(zhí)行時(shí)間提前6秒即2020-01-01 00:01:57秒,首次執(zhí)行時(shí)間為2020-01-01 00:01:00而不是2020-01-01 00:01:57,代碼snippet:
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.SECOND, -6); // L1
        Timer timer = new Timer();
        // 第一次執(zhí)行為6秒前,之后么個(gè)兩秒鐘執(zhí)行一次
        timer.schedule(new TimerTask() {
            @Override
            public void run() { // L2
                System.out.println("Scheduled exec time is : "   TimerUtils.sdf.format(scheduledExecutionTime()));
                System.out.println("Task is being executed!");
            }
        }, calendar.getTime(), 2000);

如果任務(wù)時(shí)間為3000毫秒,第一次執(zhí)行開始時(shí)間2020-01-01 00:01:00,第二次為2020-01-01 00:01:03而不是2020-01-01 00:01:02。
這里使用在任務(wù)線程休眠三秒來實(shí)現(xiàn),注釋掉L1行代碼,在L1處添加代碼休眠三秒,代碼snippet:

        Calendar calendar = Calendar.getInstance();
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Scheduled exec time is : "   TimerUtils.sdf.format(scheduledExecutionTime()));
                System.out.println("Task is being executed!");
            }
        }, calendar.getTime(), 2000);
  1. 對(duì)于fixed-reate執(zhí)行講解:
    如當(dāng)前時(shí)間2019-04-03 23:02:58,period為2000毫秒,將開始執(zhí)行時(shí)間提前6秒即2019-04-03 23:02:52秒,首次執(zhí)行時(shí)間為2019-04-03 23:02:52,控制臺(tái)會(huì)看到開始會(huì)一下子執(zhí)行如下4次任務(wù):
Current time is : 2019-04-03 23:02:58
Scheduled exec time is : 2019-04-03 23:02:52
Task is being executed!
Scheduled exec time is : 2019-04-03 23:02:54
Task is being executed!
Scheduled exec time is : 2019-04-03 23:02:56
Task is being executed!
Scheduled exec time is : 2019-04-03 23:02:58
Task is being executed!

代碼snippet:

        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.SECOND, -6); // L1
        Timer timer = new Timer();
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {// L3
                System.out.println("Scheduled exec time is : "   TimerUtils.sdf.format(scheduledExecutionTime()));
                System.out.println("Task is being executed!");
            }
        }, calendar.getTime(), 2000); 
    }

如果任務(wù)時(shí)間為3000毫秒,period為2000毫秒,當(dāng)前時(shí)間2019-04-03 23:23:22,第一次執(zhí)行開始時(shí)間2019-04-03 23:23:22,第二次執(zhí)行時(shí)間2019-04-03 23:23:24,兩個(gè)任務(wù)執(zhí)行時(shí)間段有交集。
注釋掉L1所在行,在L3處讓任務(wù)線程休眠三秒模仿執(zhí)行時(shí)間為3秒的任務(wù),代碼snippet:

        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.SECOND, -6); // L1
        Timer timer = new Timer();
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000); // L3
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Scheduled exec time is : "   TimerUtils.sdf.format(scheduledExecutionTime()));
                System.out.println("Task is being executed!");
            }
        }, calendar.getTime(), 2000);

注釋掉不需要的代碼觀察效果,演示代碼:

/*
 * DifferenceTest.java -- JDK 1.8
 */

package timer;

import java.util.Calendar;
import java.util.Timer;
import java.util.TimerTask;

/**
 * Description:
 * <p>
 * <p>
 * @author ascribed
 * @date 2019-04-03 Wed PM 21:47:38
 */

public class DifferenceTest {

    public static void main(String[] args) {
        Calendar calendar = TimerUtils.current();
        TimerUtils.miscellaneous("Current time is : ", calendar.getTime());
        // 設(shè)置成6秒前的時(shí)間,若當(dāng)前時(shí)間為2016-12-28 00:00:06
        // 那么設(shè)置之后時(shí)間變成2016-12-28 00:00:00
        calendar.add(Calendar.SECOND, -6); // L1
        Timer timer = new Timer();
        // 第一次執(zhí)行為6秒前,之后么個(gè)兩秒鐘執(zhí)行一次
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000); // L2
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Scheduled exec time is : "   TimerUtils.sdf.format(scheduledExecutionTime()));
                System.out.println("Task is being executed!");
            }
        }, calendar.getTime(), 2000); // 此處有個(gè)語法糖,編譯器生成一個(gè)匿名類繼承抽象類TimerTask通過new實(shí)例化,這并不違反抽象類不能實(shí)例化這一原則
        
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);  // L3
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Scheduled exec time is : "   TimerUtils.sdf.format(scheduledExecutionTime()));
                System.out.println("Task is being executed!");
            }
        }, calendar.getTime(), 2000); 
    }

}

4 實(shí)戰(zhàn)

實(shí)現(xiàn)兩個(gè)機(jī)器人
跳舞機(jī)器人:每隔兩秒打印最近一次計(jì)劃的時(shí)間和執(zhí)行內(nèi)容
灌水機(jī)器人:模擬往桶里倒水,直到桶里的水滿為止
灌水機(jī)器人工作流程
灌水,如果水不滿,則一直工作;如果水滿,則停止工作。
跳舞機(jī)器人
跳舞,如果水不滿,則一直工作;如果水滿,則跳舞兩秒后停止工作。
代碼清單
DancingRobot.java、WaterRobot.java和Executor.java。

/*
 * WaterRobot.java -- JDK 1.8
 */

package timer;

import java.util.Timer;
import java.util.TimerTask;

/**
 * Description:
 * <p>
 * <p>
 * @author ascribed
 * @date 2019-04-02 Tue PM 16:44:17
 */

public class WaterRobot extends TimerTask {
    
    private Timer timer;
    // 最大容量5L
    private Integer bucketCapacity = 0;
    private final String unit = "L";
    public WaterRobot(Timer timer) {
        this.timer = timer;
    }  
    
    @Override
    public void run() {
        // 灌水到桶滿為止
        if (bucketCapacity < 5) {
            System.out.println("Add 1L water into the bucket!");
            bucketCapacity  ;
        } else {
            // 水滿之后停止執(zhí)行
            System.out.println("The number of canceled task in timer is : "   timer.purge());
            cancel();
            System.out.println("The waterRot has been aborted");
            System.out.println("The number of canceled task in timer is : "   timer.purge());
            System.out.println("Current water is "   bucketCapacity   unit);
            // 等待兩秒鐘,終止timer里面的所有內(nèi)容
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            timer.cancel();
        }
    }
}
/*
 * DancingRobot.java -- JDK 1.8
 */

package timer;

import java.text.SimpleDateFormat;
import java.util.TimerTask;

/**
 * Description:
 * <p>
 * <p>
 * @author ascribed
 * @date 2019-04-02 Tue PM 16:35:12
 */

public class DancingRobot extends TimerTask {

    @Override
    public void run() {
        SimpleDateFormat sdf = new SimpleDateFormat(TimeConstants.DATE_FORMAT);
        System.out.println("Scheduled exec time is : "   sdf.format(scheduledExecutionTime())); // 獲得最近一次任務(wù)執(zhí)行的計(jì)劃時(shí)間
        System.out.println("Dancing happily!");
    }

}
/*
 * Executor.java -- JDK 1.8
 */

package timer;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Timer;

/**
 * Description:
 * <p>
 * <p>
 * @author ascribed
 * @date 2019-04-02 Tue PM 16:54:04
 */

public class Executor {

    public static void main(String[] args) {
        Timer timer = new Timer(); 
        Calendar calendar = Calendar.getInstance();
        SimpleDateFormat sdf = new SimpleDateFormat(TimeConstants.DATE_FORMAT);
        System.out.println("Current time is : "   sdf.format(calendar.getTime()));
        
        DancingRobot dr = new DancingRobot();
        WaterRobot wr = new WaterRobot(timer);
        
        timer.schedule(dr, calendar.getTime(), 2000);
        timer.scheduleAtFixedRate(wr, calendar.getTime(), 1000);
    }

}

執(zhí)行結(jié)果

Current time is : 2019-04-04 01:19:20
Scheduled exec time is : 2019-04-04 01:19:21
Dancing happily!
Add 1L water into the bucket!
Add 1L water into the bucket!
Add 1L water into the bucket!
Scheduled exec time is : 2019-04-04 01:19:23
Dancing happily!
Add 1L water into the bucket!
Add 1L water into the bucket!
Scheduled exec time is : 2019-04-04 01:19:25
Dancing happily!
The number of canceled task in timer is : 0
The waterRot has been aborted
The number of canceled task in timer is : 1
Current water is 5L

5 Timer的缺陷

天生的兩種缺陷

  • 管理并發(fā)任務(wù)的缺陷
    Timer有且僅有一個(gè)線程去執(zhí)行定時(shí)任務(wù),如果存在多個(gè)任務(wù),且任務(wù)時(shí)間過長,會(huì)導(dǎo)致執(zhí)行結(jié)果與預(yù)期不符。
    演示代碼:
/*
 * ExTimer.java -- JDK 1.8
 */

package timer;

import java.util.Calendar;
import java.util.Timer;
import java.util.TimerTask;

/**
 * Description:
 * <p>
 * <p>
 * @author ascribed
 * @date 2019-04-03 Wed PM 23:37:41
 */

public class ConTimer {
    public static void main(String[] args) {
        Timer timer = new Timer();
        ConTimerTask exTimerTask1 = new ConTimerTask("No.1", 2000);
        ConTimerTask exTimerTask2 = new ConTimerTask("No.2", 2000);
        Calendar calendar = TimerUtils.current();
        TimerUtils.miscellaneous("Current time is : ", calendar
                .getTime());
        timer.schedule(exTimerTask1, calendar.getTime());
        timer.schedule(exTimerTask2, calendar.getTime());
//        timer.scheduleAtFixedRate(exTimerTask1, calendar.getTime(), 2000);
//        timer.scheduleAtFixedRate(exTimerTask2, calendar.getTime(), 2000);
        
    }
}

class ConTimerTask extends TimerTask {
    private String name;
    private long costTime;

    public ConTimerTask(String name, long costTime) {
        this.setName(name);
        this.costTime = costTime;
    }

    @Override
    public void run() {
        System.out.println(name   "'s current exec time is : "   TimerUtils.sdf.format(Calendar.getInstance()
                .getTime())); // 輸出當(dāng)前時(shí)間
        try {
            Thread.sleep(costTime);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(name   "'s finish time is : "   TimerUtils.sdf.format(Calendar.getInstance()
                .getTime())); // 輸出costTime之后的時(shí)間
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

執(zhí)行結(jié)果:

Current time is : 2019-04-04 01:04:24
No.1's current exec time is : 2019-04-04 01:04:24
No.1's finish time is : 2019-04-04 01:04:26
No.2's current exec time is : 2019-04-04 01:04:26
No.2's finish time is : 2019-04-04 01:04:28
  • 當(dāng)任務(wù)拋出異常時(shí)的缺陷
    如果TimerTask拋出RuntimeException,Timer會(huì)停止所有任務(wù)的運(yùn)行。
    演示代碼:
/*
 * ExTimer.java -- JDK 1.8
  */

package timer;

import java.util.Timer;
import java.util.TimerTask;

/**
 * Description:
 * <p>
 * <p>
 * @author ascribed
 * @date 2019-04-04 Thu AM 00:33:14
 */

public class ExTimer {
    public static void main(String[] args) {
        Timer timer = new Timer();
        ExTimerTask task1 = new ExTimerTask("task1");
        ExTimerTask task2 = new ExTimerTask("task2");
        timer.scheduleAtFixedRate(task1, 1000, 1000);
        timer.scheduleAtFixedRate(task2, 1000, 2000 );
    }
}
class ExTimerTask extends TimerTask {
    private String name;
    
    public ExTimerTask(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        System.out.println(name);
        throw new IllegalStateException();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

執(zhí)行結(jié)果:

task1
Exception in thread "Timer-0" java.lang.IllegalStateException
    at timer.ExTimerTask.run(ExTimer.java:37)
    at java.util.TimerThread.mainLoop(Timer.java:555)
    at java.util.TimerThread.run(Timer.java:505)
  • TimerTask是一次性
    定時(shí)器(Timer)的TimerTask實(shí)例只能schedule一次,再次調(diào)用會(huì)拋出運(yùn)行時(shí)異常IllegalStateException,這是一個(gè)運(yùn)行時(shí)異常。
    解決方法有二:一是反射修改state字段,二是每次用new一個(gè)TimerTask。

    Timer的使用禁區(qū)

  • 對(duì)時(shí)效性要求較高的多任務(wù)并發(fā)作業(yè)
  • 對(duì)復(fù)雜的任務(wù)的調(diào)度

    ?

來源:https://www./content-4-655051.html

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多