線程池之ScheduledThreadPoolExecutor概述

簡介

在探討時 ThreadPoolExecutor 只介紹了FixedThreadPool抑堡、CachedThreadPool巡雨、SingleThreadExecutor骇径,并沒有去介紹ScheduledThreadPoolExecutor炊林,因為 ScheduledThreadPoolExecutor 與其他線程池的概念有些區(qū)別堵未,它是一個支持任務周期性調(diào)度的線程池。

ScheduledThreadPoolExecutor 繼承 ThreadPoolExecutor赂苗,同時通過實現(xiàn) ScheduledExecutorSerivce 來擴展基礎(chǔ)線程池的功能愉耙,使其擁有了調(diào)度能力。其整個調(diào)度的核心在于內(nèi)部類 DelayedWorkQueue 拌滋,一個有序的延時隊列朴沿。

ScheduledThreadPoolExecutor類圖.png

ScheduledThreadPoolExecutor 的出現(xiàn),很好的彌補了傳統(tǒng) Timer 的不足,具體對比看下表:

Timer ScheduledThreadPoolExecutor
線程 單線程 多線程
多任務 任務之間相互影響 任務之間不影響
調(diào)度時間 絕對時間 相對時間
異常 單任務異常赌渣,
后續(xù)任務受影響
無影響

構(gòu)造方法

ScheduledThreadPoolExecutor有三個構(gòu)造形式:

public ScheduledThreadPoolExecutor(int corePoolSize,
                                    ThreadFactory threadFactory) {
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
          new DelayedWorkQueue(), threadFactory);
}

public ScheduledThreadPoolExecutor(int corePoolSize,
                                   RejectedExecutionHandler handler) {
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
          new DelayedWorkQueue(), handler);
}

public ScheduledThreadPoolExecutor(int corePoolSize,
                                   ThreadFactory threadFactory,
                                   RejectedExecutionHandler handler) {
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
          new DelayedWorkQueue(), threadFactory, handler);
}

關(guān)于父類的構(gòu)造可參見 ThreadPoolExecutor魏铅。當然我們也可以使用工具類Executors的newScheduledThreadPool的方法,快速創(chuàng)建坚芜。注意這里使用的DelayedWorkQueue沦零。

ScheduledThreadPoolExecutor沒有提供帶有最大線程數(shù)的構(gòu)造函數(shù)的,默認是Integer.MAX_VALUE货岭,說明其可以無限制的開啟任意線程執(zhí)行任務路操,在大量任務系統(tǒng),應注意這一點千贯,避免內(nèi)存溢出屯仗。

核心方法

核心方法主要介紹ScheduledThreadPoolExecutor的調(diào)度方法,其他方法與 ThreadPoolExecutor 一致搔谴。調(diào)度方法均由 ScheduledExecutorService 接口定義:

public interface ScheduledExecutorService extends ExecutorService {
    // 特定時間延時后執(zhí)行一次Runnable
    public ScheduledFuture<?> schedule(Runnable command,
                                       long delay, TimeUnit unit);
    // 特定時間延時后執(zhí)行一次Callable
    public <V> ScheduledFuture<V> schedule(Callable<V> callable,
                                           long delay, TimeUnit unit);
    // 固定周期執(zhí)行任務(與任務執(zhí)行時間無關(guān)魁袜,周期是固定的)
    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                                  long initialDelay,
                                                  long period,
                                                  TimeUnit unit);
     // 固定延時執(zhí)行任務(與任務執(zhí)行時間有關(guān),延時從上一次任務完成后開始)
    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                                                     long initialDelay,
                                                     long delay,
                                                     TimeUnit unit);
}

代碼中注釋了每個方法的作用敦第,需注意固定周期與固定延時的區(qū)別峰弹。下面分別對這些方法進行測試:

public class ScheduledPoolTest {
    
    private static final SimpleDateFormat FORMAT = new SimpleDateFormat("hh:mm:ss");
    
    private static final Random RANDOM = new Random();
    
    /**
     * 輸出:
     *  11:04:32
        11:04:35
     */
    public static void schedule() {
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
        printTime();
        scheduledExecutorService.schedule(new Task(), 3, TimeUnit.SECONDS);
    }
    
    /**
     * 輸出:
     *  11:05:34
        11:05:36
        11:05:46
        11:05:56
        11:06:06
        11:06:16
        ......
     */
    public static void scheduleAtFixedRate() {
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
        printTime();
        scheduledExecutorService.scheduleAtFixedRate(new Task(), 2, 10, TimeUnit.SECONDS);
    }
    
    /**
     * 輸出:
     *  11:07:39
        11:07:41
        11:07:54
        11:08:08
        11:08:22
        11:08:33
        ......
     */
    public static void scheduleWithFixedDelay() {
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
        printTime();
        scheduledExecutorService.scheduleWithFixedDelay(new Task(), 2, 10, TimeUnit.SECONDS);
    }
    
    static class Task implements Runnable{
        public void run() {
            printTime();
            try {
                Thread.sleep(RANDOM.nextInt(5) * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    public static void printTime() {
        Date date = new Date();
        System.out.println(FORMAT.format(date));
    }
}

為了體現(xiàn)scheduleAtFixedRate和scheduleWithFixedDelay的差別,在代碼中我們加入了隨機睡眠時間芜果,使任務執(zhí)行不確定鞠呈。從注釋中的輸出我們可以看到scheduleAtFixedRate的任務運行周期不受任務執(zhí)行時間的影響,而scheduleWithFixedDelay的任務運行周期受任務執(zhí)行時間影響較大右钾。

但需注意蚁吝,如果任務的執(zhí)行時間超過任務調(diào)度周期,比如任務執(zhí)行需要10s舀射,而給定執(zhí)行時間間隔是5s的話窘茁,任務的調(diào)度是在任務10s執(zhí)行完之后立即重新執(zhí)行,而不是5s的周期脆烟。

總結(jié)

ScheduledThreadPoolExecutor 在 ThreadPoolExecutor 的基礎(chǔ)上擴展了 線程周期調(diào)度功能山林,使用時應注意控制其調(diào)度的時間點。

多線程系列目錄(不斷更新中):
線程啟動原理
線程中斷機制
多線程實現(xiàn)方式
FutureTask實現(xiàn)原理
線程池之ThreadPoolExecutor概述
線程池之ThreadPoolExecutor使用
線程池之ThreadPoolExecutor狀態(tài)控制
線程池之ThreadPoolExecutor執(zhí)行原理
線程池之ScheduledThreadPoolExecutor概述
線程池之ScheduledThreadPoolExecutor調(diào)度原理
線程池的優(yōu)雅關(guān)閉實踐

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末邢羔,一起剝皮案震驚了整個濱河市驼抹,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌张抄,老刑警劉巖砂蔽,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件洼怔,死亡現(xiàn)場離奇詭異署惯,居然都是意外死亡,警方通過查閱死者的電腦和手機镣隶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進店門极谊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來诡右,“玉大人,你說我怎么就攤上這事轻猖》牵” “怎么了?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵咙边,是天一觀的道長猜煮。 經(jīng)常有香客問我,道長败许,這世上最難降的妖魔是什么王带? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮市殷,結(jié)果婚禮上愕撰,老公的妹妹穿的比我還像新娘。我一直安慰自己醋寝,他們只是感情好搞挣,可當我...
    茶點故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著音羞,像睡著了一般囱桨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上嗅绰,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天蝇摸,我揣著相機與錄音,去河邊找鬼办陷。 笑死貌夕,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的民镜。 我是一名探鬼主播啡专,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼制圈!你這毒婦竟也來了们童?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤鲸鹦,失蹤者是張志新(化名)和其女友劉穎慧库,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體馋嗜,經(jīng)...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡齐板,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片甘磨。...
    茶點故事閱讀 40,427評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡橡羞,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出济舆,到底是詐尸還是另有隱情卿泽,我是刑警寧澤,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布滋觉,位于F島的核電站签夭,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏椎侠。R本人自食惡果不足惜覆致,卻給世界環(huán)境...
    茶點故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望肺蔚。 院中可真熱鬧煌妈,春花似錦、人聲如沸宣羊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽仇冯。三九已至之宿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間苛坚,已是汗流浹背比被。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留泼舱,地道東北人等缀。 一個月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像娇昙,于是被迫代替她去往敵國和親尺迂。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,440評論 2 359

推薦閱讀更多精彩內(nèi)容