xylz,imxylz

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

             :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            111 隨筆 :: 10 文章 :: 2680 評論 :: 0 Trackbacks

          公告

          常用鏈接

          留言簿(149)

          隨筆分類(137)

          隨筆檔案(107)

          文章分類(12)

          文章檔案(12)

          友情鏈接

          搜索

          積分與排名

          最新評論

          閱讀排行榜

          評論排行榜

          [本文地址:http://www.aygfsteel.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://www.aygfsteel.com/Files/xylz/Inside.Java.Concurrency_32.ThreadPool.part5_ScheduledExecutorService.pdf]


          ©2009-2014 IMXYLZ |求賢若渴
          posted on 2011-01-10 23:39 imxylz 閱讀(14477) 評論(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
          主站蜘蛛池模板: 英吉沙县| 邵武市| 奇台县| 锦屏县| 澄迈县| 德州市| 阳信县| 福贡县| 扎赉特旗| 鄯善县| 安平县| 武乡县| 仙居县| 武隆县| 陆丰市| 远安县| 泰和县| 章丘市| 新沂市| 南投市| 丹凤县| 弋阳县| 河间市| 芷江| 万州区| 嘉祥县| 隆德县| 阜南县| 洪雅县| 吕梁市| 砚山县| 海宁市| 镇康县| 疏附县| 辽阳市| 北安市| 扬州市| 桦南县| 安徽省| 长春市| 石家庄市|