<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    xylz,imxylz

    關注后端架構、中間件、分布式和并發編程

       :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      111 隨筆 :: 10 文章 :: 2680 評論 :: 0 Trackbacks
    [本文地址:http://m.tkk7.com/Files/xylz/Inside.Java.Concurrency_32.ThreadPool.part5_ScheduledExecutorService.pdf]

    周期性任務調度前世

    在JDK 5.0之前,java.util.Timer/TimerTask是唯一的內置任務調度方法,而且在很長一段時間里很熱衷于使用這種方式進行周期性任務調度。

    首先研究下Timer/TimerTask的特性(至于javax.swing.Timer就不再研究了)。

    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);
    }
    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);
    }

     

    public class Timer {

       
    private TaskQueue queue = new TaskQueue();
       
    /**
         * The timer thread.
        
    */
       
    private TimerThread thread = new TimerThread(queue);
     

     

    java.util.TimerThread.mainLoop()

    private void mainLoop() {
       
    while (true) {
           
    try {
                TimerTask task;
               
    boolean taskFired;
               
    synchronized(queue) {
                   
    // Wait for queue to become non-empty
                    while (queue.isEmpty() && newTasksMayBeScheduled)
                        queue.wait();
                   
    if (queue.isEmpty())
                       
    break; // Queue is empty and will forever remain; die
    。。。。。。
                    
                   
    if (!taskFired) // Task hasn't yet fired; wait
                        queue.wait(executionTime - currentTime);
                }
               
    if (taskFired)  // Task fired; run it, holding no locks
                    task.run();
            }
    catch(InterruptedException e) {
            }
        }
    }

     

    上面三段代碼反映了Timer/TimerTask的以下特性:

    • Timer對任務的調度是基于絕對時間的。
    • 所有的TimerTask只有一個線程TimerThread來執行,因此同一時刻只有一個TimerTask在執行。
    • 任何一個TimerTask的執行異常都會導致Timer終止所有任務。
    • 由于基于絕對時間并且是單線程執行,因此在多個任務調度時,長時間執行的任務被執行后有可能導致短時間任務快速在短時間內被執行多次或者干脆丟棄多個任務。

    由于Timer/TimerTask有這些特點(缺陷),因此這就導致了需要一個更加完善的任務調度框架來解決這些問題。

    周期性任務調度今生

    java.util.concurrent.ScheduledExecutorService的出現正好彌補了Timer/TimerTask的缺陷。

    public interface ScheduledExecutorService extends ExecutorService {
       
    public ScheduledFuture<?> schedule(Runnable command,
                          
    long delay, TimeUnit unit);
     
       
    public <V> ScheduledFuture<V> schedule(Callable<V> callable,
                          
    long delay, TimeUnit unit);
       
    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                             
    long initialDelay,
                             
    long period,
                              TimeUnit unit);
     
       
    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                                
    long initialDelay,
                                
    long delay,
                                 TimeUnit unit);
    }

     

    首先ScheduledExecutorService基于ExecutorService,是一個完整的線程池調度。另外在提供線程池的基礎上增加了四個調度任務的API。

    • schedule(Runnable command,long delay, TimeUnit unit):在指定的延遲時間一次性啟動任務(Runnable),沒有返回值。
    • schedule(Callable<V> callable, long delay, TimeUnit unit):在指定的延遲時間一次性啟動任務(Callable),攜帶一個結果。
    • scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit):建并執行一個在給定初始延遲后首次啟用的定期操作,后續操作具有給定的周期;也就是將在 initialDelay 后開始執行,然后在 initialDelay+period 后執行,接著在 initialDelay + 2 * period 后執行,依此類推。如果任務的任何一個執行遇到異常,則后續執行都會被取消。否則,只能通過執行程序的取消或終止方法來終止該任務。如果此任務的任何一個執行要花費比其周期更長的時間,則將推遲后續執行,但不會同時執行。
    • scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit):創建并執行一個在給定初始延遲后首次啟用的定期操作,隨后,在每一次執行終止和下一次執行開始之間都存在給定的延遲。如果任務的任一執行遇到異常,就會取消后續執行。否則,只能通過執行程序的取消或終止方法來終止該任務。

    上述API解決了以下幾個問題:

    • ScheduledExecutorService任務調度是基于相對時間,不管是一次性任務還是周期性任務都是相對于任務加入線程池(任務隊列)的時間偏移。
    • 基于線程池的ScheduledExecutorService允許多個線程同時執行任務,這在添加多種不同調度類型的任務是非常有用的。
    • 同樣基于線程池的ScheduledExecutorService在其中一個任務發生異常時會退出執行線程,但同時會有新的線程補充進來進行執行。
    • ScheduledExecutorService可以做到不丟失任務。

    下面的例子演示了一個任務周期性調度的例子。

    package xylz.study.concurrency.executor;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ScheduledExecutorService;
    import java.util.concurrent.TimeUnit;

    public class ScheduledExecutorServiceDemo {
       
    public static void main(String[] args) throws Exception{
            ScheduledExecutorService execService
    =   Executors.newScheduledThreadPool(3);
            execService.scheduleAtFixedRate(
    new Runnable() {
               
    public void run() {
                    System.out.println(Thread.currentThread().getName()
    +" -> "+System.currentTimeMillis());
                   
    try {
                        Thread.sleep(
    2000L);
                    }
    catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            },
    1, 1, TimeUnit.SECONDS);
           
    //
            execService.scheduleWithFixedDelay(new Runnable() {
               
    public void run() {
                    System.out.println(Thread.currentThread().getName()
    +" -> "+System.currentTimeMillis());
                   
    try {
                        Thread.sleep(
    2000L);
                    }
    catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            },
    1, 1, TimeUnit.SECONDS);
            Thread.sleep(
    5000L);
            execService.shutdown();
        }
    }

     

    一次可能的輸出如下:

    pool-1-thread-1 -> 1294672392657
    pool
    -1-thread-2 -> 1294672392659
    pool
    -1-thread-1 -> 1294672394657
    pool
    -1-thread-2 -> 1294672395659
    pool
    -1-thread-1 -> 1294672396657

     

    在這個例子中啟動了默認三個線程的線程池,調度兩個周期性任務。第一個任務是每隔1秒執行一次,第二個任務是以固定1秒的間隔執行,這兩個任務每次執行的時間都是2秒。上面的輸出有以下幾點結論:

    • 任務是在多線程中執行的,同一個任務應該是在同一個線程中執行。
    • scheduleAtFixedRate是每次相隔相同的時間執行任務,如果任務的執行時間比周期還長,那么下一個任務將立即執行。例如這里每次執行時間2秒,而周期時間只有1秒,那么每次任務開始執行的間隔時間就是2秒。
    • scheduleWithFixedDelay描述是下一個任務的開始時間與上一個任務的結束時間間隔相同。流入這里每次執行時間2秒,而周期時間是1秒,那么兩個任務開始執行的間隔時間就是2+1=3秒。

    事實上ScheduledExecutorService的實現類ScheduledThreadPoolExecutor是繼承線程池類ThreadPoolExecutor的,因此它擁有線程池的全部特性。但是同時又是一種特殊的線程池,這個線程池的線程數大小不限,任務隊列是基于DelayQueue的無限任務隊列。具體的結構和算法在以后的章節中分析。

    由于ScheduledExecutorService擁有Timer/TimerTask的全部特性,并且使用更簡單,支持并發,而且更安全,因此沒有理由繼續使用Timer/TimerTask,完全可以全部替換。需要說明的一點事構造ScheduledExecutorService線程池的核心線程池大小要根據任務數來定,否則可能導致資源的浪費。

     

    [本文地址:http://m.tkk7.com/Files/xylz/Inside.Java.Concurrency_32.ThreadPool.part5_ScheduledExecutorService.pdf]


    ©2009-2014 IMXYLZ |求賢若渴
    posted on 2011-01-10 23:39 imxylz 閱讀(14461) 評論(32)  編輯  收藏 所屬分類: Java Concurrency

    評論

    # re: 深入淺出 Java Concurrency (32): 線程池 part 5 周期性任務調度 2011-01-11 12:06 打底褲
    果然深入淺出哈  回復  更多評論
      

    # re: 深入淺出 Java Concurrency (32): 線程池 part 5 周期性任務調度 2011-01-12 15:59 青菜貓
    樓主確實不錯,。有機會來杭州一起給我們團隊講下  回復  更多評論
      

    # re: 深入淺出 Java Concurrency (32): 線程池 part 5 周期性任務調度 2011-02-09 16:28 wells
    海,兄弟可以交流下  回復  更多評論
      

    # re: 深入淺出 Java Concurrency (32): 線程池 part 5 周期性任務調度 2011-02-09 16:30 wells
    我是淘寶技術人員,有幾個問題想跟你交流下,我的郵箱是qing.yinbo@gmail.com,通過郵件我們可以交流下,期待你的email  回復  更多評論
      

    # re: 深入淺出 Java Concurrency (32): 線程池 part 5 周期性任務調度 2013-11-08 12:34 高永飛
    同樣基于線程池的ScheduledExecutorService在其中一個任務發生異常時會退出執行線程,但同時會有新的線程補充進來進行執行

    這句話有問題,任務發生RuntimeException時,執行該任務的線程會終止,這句話沒有問題。但是不會有新的線程補充進來執行。因為執行任務的后臺線程是調用scheduleWithFixedDelay或scheduleWithFixedDelay時創建的,可以參考ScheduledThreadPoolExecutor.delayedExecute的prestartCoreThread()。

    也就是說,如果想讓任務發生異常時照樣按時執行后續的任務,需要在任務里catch住所有異常。

    舉個例子,
    ScheduledExecutorService exec = Executors.newScheduledThreadPool(2);
    exec.scheduleWithFixedDelay(new Runnable() 。。。

    ScheduledExecutorService不會因為設置了size是2,而會在任務發生異常時,再啟動一個線程繼續執行。

    技術性的文章建議博主寫代碼檢驗每一句話,尤其是博主這種瀏覽量大的文章。
    不過真心贊一下,博主寫的這一系列文章很不錯!

    如果我說的有問題,請及時指正 qq:554312685  回復  更多評論
      

    # John 2014-05-02 03:26 Smithd559
    Good writeup, I am normal visitor of ones blog, maintain up the excellent operate, and It's going to be a regular visitor for a lengthy time. kbceedeffdadcddg  回復  更多評論
      

    # Good info 2014-05-04 21:05 Pharmd383
    Very nice site!  回復  更多評論
      

    # cheap cialis online 2014-05-16 16:48 cialis
    Hello!
      回復  更多評論
      

    # cheap cialis 2014-05-16 16:49 cheap_cialis
    Hello!
      回復  更多評論
      

    # viagra sale 2014-05-17 05:07 viagra_sale
    Hello!
      回復  更多評論
      

    # cialis tadalafil cheapest online 2014-05-17 05:28 tadalafil
    Hello!
      回復  更多評論
      

    # cialis online 2014-05-20 15:19 cialis_online
    Hello!
      回復  更多評論
      

    # viagra price 2014-05-20 15:20 viagra_price
    Hello!
      回復  更多評論
      

    # cheap cialis 2014-07-14 18:44 cheap_cialis
    Hello!
      回復  更多評論
      

    # cheap viagra 2014-07-14 18:45 cheap_viagra
    Hello!
      回復  更多評論
      

    # http://canadianviagragen7a.com/ 2014-07-17 15:14 with
    Hello!
      回復  更多評論
      

    # http://viagra7withoutprescription.com/ 2014-07-17 18:09 discount
    Hello!
      回復  更多評論
      

    # http://cheapgeneric7viagra.com/ 2014-07-17 18:10 discount
    Hello!
      回復  更多評論
      

    # buy generic cialis 2014-07-17 23:53 generic
    Hello!
      回復  更多評論
      

    # cialis fast delivery 2015-04-29 19:50 fast
    Hello!
      回復  更多評論
      

    # viagra fast delivery 2015-04-29 19:50 fast
    Hello!
      回復  更多評論
      

    # John 2015-06-01 07:45 Smithc667
    Thanksamundo for the post.Really thank you! Awesome. edebdbceaekadffd  回復  更多評論
      

    # cialis side effects 2016-03-30 22:23 side
    Hello!
      回復  更多評論
      

    # cialis 2016-04-05 23:27 cialis
    Hello!
      回復  更多評論
      

    # dosage of viagra 2016-04-05 23:27 of
    Hello!
      回復  更多評論
      

    # cialis 2016-04-05 23:28 cialis
    Hello!
      回復  更多評論
      

    # viagra 2016-04-05 23:29 viagra
    Hello!
      回復  更多評論
      

    # cialis 2016-04-06 07:16 cialis
    Hello!
      回復  更多評論
      

    # dosage of viagra 2016-04-06 07:16 of
    Hello!
      回復  更多評論
      

    # order cialis 2016-04-06 07:17 order_cialis
    Hello!
      回復  更多評論
      

    # order viagra 2016-04-06 07:18 order_viagra
    Hello!
      回復  更多評論
      

    # re: 深入淺出 Java Concurrency (32): 線程池 part 5 周期性任務調度 2018-08-03 17:21 bboymars
    任務是在多線程中執行的,同一個任務應該是在同一個線程中執行。
    這個結論在我機子上運行不對,我運行如下:
    pool-1-thread-1 -> 任務a -> 1533287852227
    pool-1-thread-2 -> 任務b -> 1533287852227
    pool-1-thread-2 -> 任務a -> 1533287854227
    pool-1-thread-1 -> 任務b -> 1533287855230
    pool-1-thread-2 -> 任務a -> 1533287856230
    pool-1-thread-2 -> 任務a -> 1533287858234
    pool-1-thread-1 -> 任務b -> 1533287858234
    pool-1-thread-3 -> 任務a -> 1533287860236
    pool-1-thread-2 -> 任務b -> 1533287861237
    pool-1-thread-3 -> 任務a -> 1533287862237
    pool-1-thread-2 -> 任務a -> 1533287864240
    pool-1-thread-1 -> 任務b -> 1533287864240
    pool-1-thread-2 -> 任務a -> 1533287866244  回復  更多評論
      


    ©2009-2014 IMXYLZ
    主站蜘蛛池模板: 中文字幕成人免费视频| 免费久久人人爽人人爽av | 国产日产亚洲系列最新| 亚洲一级毛片免费在线观看| 国产午夜无码精品免费看| 一区二区三区免费电影| 亚洲成熟丰满熟妇高潮XXXXX| 久久久久亚洲av无码专区喷水| 亚洲一区二区三区在线播放 | 国产一级淫片视频免费看| 亚洲国产一成久久精品国产成人综合| 精品亚洲综合在线第一区| 亚洲最大成人网色香蕉| 9久热精品免费观看视频| 91热久久免费精品99| 7723日本高清完整版免费| 最新中文字幕免费视频| 免费乱理伦在线播放| 亚洲成AV人片在| 亚洲依依成人精品| 国产在亚洲线视频观看| 久久久久久久99精品免费观看| 91福利免费体验区观看区| 日韩免费毛片视频| 亚洲AV无码不卡在线播放| 亚洲国产精品成人综合久久久 | 久久99精品视免费看| 色播在线永久免费视频| 亚洲成在人天堂一区二区| 精品无码专区亚洲| 91免费在线播放| 国产v亚洲v天堂无码网站| 亚洲人成网站在线观看播放动漫| 日韩在线观看视频免费| 永久免费AV无码网站在线观看| 亚洲天堂男人天堂| 免费A级毛片无码A∨| 久久久综合亚洲色一区二区三区| 九九九精品视频免费| 亚洲av再在线观看| jizz免费在线观看|