精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

并發編程之定時任務&定時線程池原理解析

開發 前端
線程池的具體實現有兩種,分別是ThreadPoolExecutor 默認線程池和ScheduledThreadPoolExecutor 定時線程池,上一篇已經分析過ThreadPoolExecutor原理與使用了,本篇我們來重點分析下ScheduledThreadPoolExecutor的原理與使用。

[[356766]]

 前言

線程池的具體實現有兩種,分別是ThreadPoolExecutor 默認線程池和ScheduledThreadPoolExecutor 定時線程池,上一篇已經分析過ThreadPoolExecutor原理與使用了,本篇我們來重點分析下ScheduledThreadPoolExecutor的原理與使用。

《并發編程之Executor線程池原理與源碼解讀》

ScheduledThreadPoolExecutor

ScheduledThreadPoolExecutor 與 ThreadPoolExecutor 線程池的概念有些區別,它是一個支持任務周期性調度的線程池。

ScheduledThreadPoolExecutor 繼承 ThreadPoolExecutor,同時通過實現 ScheduledExecutorSerivce 來擴展基礎線程池的功能,使其擁有了調度能力。其整個調度的核心在于內部類 DelayedWorkQueue ,一個有序的延時隊列。

定時線程池類的類結構圖如下:

ScheduledThreadPoolExecutor 的出現,很好的彌補了傳統 Timer 的不足,具體對比看下表:

TimerScheduledThreadPoolExecutor線程單線程多線程多任務任務之間相互影響任務之間不影響調度時間絕對時間相對時間異常單任務異常,后續任務受影響無影響

工作原理

它用來處理延時任務或定時任務

它接收SchduledFutureTask類型的任務,是線程池調度任務的最小單位,有三種提交任務的方式:

  1. schedule,特定時間延時后執行一次任務
  2. scheduledAtFixedRate,固定周期執行任務(與任務執行時間無關,周期是固定的)
  3. scheduledWithFixedDelay,固定延時執行任務(與任務執行時間有關,延時從上一次任務完成后開始)

它采用 DelayedWorkQueue 存儲等待的任務

  1. DelayedWorkQueue 內部封裝了一個 PriorityQueue ,它會根據 time 的先后時間排序,若 time 相同則根據 sequenceNumber 排序;
  2. DelayedWorkQueue 也是一個無界隊列;

因為前面講阻塞隊列實現的時候,已經對DelayedWorkQueue進行了說明,更多內容請查看《阻塞隊列 — DelayedWorkQueue源碼分析》

工作線程的執行過程:

  • 工作線程會從DelayedWorkerQueue取已經到期的任務去執行;
  • 執行結束后重新設置任務的到期時間,再次放回DelayedWorkerQueue。

take方法是什么時候調用的呢? 在ThreadPoolExecutor中,getTask方法,工作線程會循環地從workQueue中取任務。但定時任務卻不同,因為如果一旦getTask方法取出了任務就開始執行了,而這時可能還沒有到執行的時間,所以在take方法中,要保證只有在到指定的執行時間的時候任務才可以被取走。

PS:對于以上原理的理解,可以通過下面的源碼分析加深印象。

源碼分析

構造方法

ScheduledThreadPoolExecutor有四個構造形式:

  1. public ScheduledThreadPoolExecutor(int corePoolSize) { 
  2.  super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, 
  3.   new DelayedWorkQueue()); 
  4.  
  5. public ScheduledThreadPoolExecutor(int corePoolSize, 
  6.                                        ThreadFactory threadFactory) { 
  7.  super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, 
  8.      new DelayedWorkQueue(), threadFactory); 
  9.  
  10. public ScheduledThreadPoolExecutor(int corePoolSize, 
  11.                                        RejectedExecutionHandler handler) { 
  12.  super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, 
  13.   new DelayedWorkQueue(), handler); 
  14.  
  15. public ScheduledThreadPoolExecutor(int corePoolSize, 
  16.                                        ThreadFactory threadFactory, 
  17.                                        RejectedExecutionHandler handler) { 
  18.  super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, 
  19.      new DelayedWorkQueue(), threadFactory, handler); 

 當然我們也可以使用工具類Executors的newScheduledThreadPool的方法,快速創建。注意這里使用的DelayedWorkQueue。

ScheduledThreadPoolExecutor沒有提供帶有最大線程數的構造函數的,默認是Integer.MAX_VALUE,說明其可以無限制的開啟任意線程執行任務,在大量任務系統,應注意這一點,避免內存溢出。

核心方法

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

  1. public interface ScheduledExecutorService extends ExecutorService { 
  2.     // 特定時間延時后執行一次Runnable 
  3.     public ScheduledFuture<?> schedule(Runnable command, 
  4.                                        long delay, TimeUnit unit); 
  5.     // 特定時間延時后執行一次Callable 
  6.     public <V> ScheduledFuture<V> schedule(Callable<V> callable, 
  7.                                            long delay, TimeUnit unit); 
  8.     // 固定周期執行任務(與任務執行時間無關,周期是固定的) 
  9.     public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, 
  10.                                                   long initialDelay, 
  11.                                                   long period, 
  12.                                                   TimeUnit unit); 
  13.      // 固定延時執行任務(與任務執行時間有關,延時從上一次任務完成后開始) 
  14.     public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, 
  15.                                                      long initialDelay, 
  16.                                                      long delay, 
  17.                                                      TimeUnit unit); 

 我們再來看一下接口的實現,具體是怎么來實現線程池任務的提交。因為最終都回調用 delayedExecute 提交任務。所以,我們這里只分析schedule方法,該方法是指任務在指定延遲時間到達后觸發,只會執行一次。源代碼如下:

  1. public ScheduledFuture<?> schedule(Runnable command, 
  2.                                    long delay, 
  3.                                    TimeUnit unit) { 
  4.     //參數校驗 
  5.     if (command == null || unit == null
  6.         throw new NullPointerException(); 
  7.     //這里是一個嵌套結構,首先把用戶提交的任務包裝成ScheduledFutureTask 
  8.     //然后在調用decorateTask進行包裝,該方法是留給用戶去擴展的,默認是個空方法 
  9.     RunnableScheduledFuture<?> t = decorateTask(command, 
  10.         new ScheduledFutureTask<Void>(command, null
  11.                                       triggerTime(delay, unit))); 
  12.    //包裝好任務以后,就進行提交了 
  13.  delayedExecute(t); 
  14.     return t; 

 delayedExecute 任務提交方法:

  1. private void delayedExecute(RunnableScheduledFuture<?> task) { 
  2.     //如果線程池已經關閉,則使用拒絕策略把提交任務拒絕掉 
  3.  if (isShutdown()) 
  4.         reject(task); 
  5.     else { 
  6.   //與ThreadPoolExecutor不同,這里直接把任務加入延遲隊列 
  7.         super.getQueue().add(task);//使用用的DelayedWorkQueue 
  8.   //如果當前狀態無法執行任務,則取消 
  9.         if (isShutdown() && 
  10.             !canRunInCurrentRunState(task.isPeriodic()) && 
  11.             remove(task)) 
  12.             task.cancel(false); 
  13.         else 
  14.          //這里是增加一個worker線程,避免提交的任務沒有worker去執行 
  15.          //原因就是該類沒有像ThreadPoolExecutor一樣,woker滿了才放入隊列 
  16.            ensurePrestart(); 
  17.     } 

 我們可以看到提交到線程池的任務都包裝成了 ScheduledFutureTask,繼續往下我們再來研究下。

ScheduledFutureTask

從ScheduledFutureTask類的定義可以看出,ScheduledFutureTask類是ScheduledThreadPoolExecutor類的私有內部類,繼承了FutureTask類,并實現了RunnableScheduledFuture接口。也就是說,ScheduledFutureTask具有FutureTask類的所有功能,并實現了RunnableScheduledFuture接口的所有方法。ScheduledFutureTask類的定義如下所示:

  1. private class ScheduledFutureTask<V> extends FutureTask<V> implements RunnableScheduledFuture<V> 

ScheduledFutureTask類繼承圖如下:


成員變量

SchduledFutureTask接收的參數(成員變量):

  1. // 任務開始的時間 
  2.  
  3. private long time
  4.  
  5. // 任務添加到ScheduledThreadPoolExecutor中被分配的唯一序列號 
  6.  
  7. private final long sequenceNumber; 
  8.  
  9. // 任務執行的時間間隔 
  10.  
  11. private final long period; 
  12.  
  13. //ScheduledFutureTask對象,實際指向當前對象本身 
  14.  
  15. RunnableScheduledFuture outerTask = this; 
  16.  
  17. //當前任務在延遲隊列中的索引,能夠更加方便的取消當前任務 
  18.  
  19. int heapIndex; 

 解析:

  • sequenceNumber:任務添加到ScheduledThreadPoolExecutor中被分配的唯一序列號,可以根據這個序列號確定唯一的一個任務,如果在定時任務中,如果一個任務是周期性執行的,但是它們的sequenceNumber的值相同,則被視為是同一個任務。
  • time:下一次執行任務的時間。
  • period:任務的執行周期。
  • outerTask:ScheduledFutureTask對象,實際指向當前對象本身。此對象的引用會被傳入到周期性執行任務的ScheduledThreadPoolExecutor類的reExecutePeriodic方法中。
  • heapIndex:當前任務在延遲隊列中的索引,這個索引能夠更加方便的取消當前任務。

構造方法

ScheduledFutureTask類繼承了FutureTask類,并實現了RunnableScheduledFuture接口。在ScheduledFutureTask類中提供了如下構造方法。

  1. ScheduledFutureTask(Runnable r, V result, long ns) { 
  2.  super(r, result); 
  3.  this.time = ns; 
  4.  this.period = 0; 
  5.  this.sequenceNumber = sequencer.getAndIncrement(); 
  6.  
  7. ScheduledFutureTask(Runnable r, V result, long ns, long period) { 
  8.  super(r, result); 
  9.  this.time = ns; 
  10.  this.period = period; 
  11.  this.sequenceNumber = sequencer.getAndIncrement(); 
  12.  
  13. ScheduledFutureTask(Callable<V> callable, long ns) { 
  14.  super(callable); 
  15.  this.time = ns; 
  16.  this.period = 0; 
  17.  this.sequenceNumber = sequencer.getAndIncrement(); 

 FutureTask的構造方法如下:

  1. public FutureTask(Runnable runnable, V result) { 
  2.  this.callable = Executors.callable(runnable, result); 
  3.  this.state = NEW;       // ensure visibility of callable 

 通過源碼可以看到,在ScheduledFutureTask類的構造方法中,首先會調用FutureTask類的構造方法為FutureTask類的callable和state成員變量賦值,接下來為ScheduledFutureTask類的time、period和sequenceNumber成員變量賦值。理解起來比較簡單。

getDelay方法

我們先來看getDelay方法的源碼,如下所示:

  1. //獲取下次執行任務的時間距離當前時間的納秒數 
  2. public long getDelay(TimeUnit unit) { 
  3.  return unit.convert(time - now(), NANOSECONDS); 

 getDelay方法比較簡單,主要用來獲取下次執行任務的時間距離當前系統時間的納秒數。

compareTo方法

ScheduledFutureTask類在類的結構上實現了Comparable接口,compareTo方法主要是對Comparable接口定義的compareTo方法的實現。源碼如下所示:

  1. public int compareTo(Delayed other) { 
  2.  if (other == this)  
  3.   return 0; 
  4.  if (other instanceof ScheduledFutureTask) { 
  5.   ScheduledFutureTask<?> x = (ScheduledFutureTask<?>)other; 
  6.   long diff = time - x.time
  7.   if (diff < 0) 
  8.    return -1; 
  9.   else if (diff > 0) 
  10.    return 1; 
  11.   else if (sequenceNumber < x.sequenceNumber) 
  12.    return -1; 
  13.   else 
  14.    return 1; 
  15.  } 
  16.  long diff = getDelay(NANOSECONDS) - other.getDelay(NANOSECONDS); 
  17.  return (diff < 0) ? -1 : (diff > 0) ? 1 : 0; 

 這段代碼看上去好像是對各種數值類型數據的比較,本質上是對延遲隊列中的任務進行排序。排序規則為:

  • 首先比較延遲隊列中每個任務下次執行的時間,下次執行時間距離當前時間短的任務會排在前面;
  • 如果下次執行任務的時間相同,則會比較任務的sequenceNumber值,sequenceNumber值小的任務會排在前面。

isPeriodic方法

isPeriodic方法的源代碼如下所示:

  1. //判斷是否是周期性任務 
  2. public boolean isPeriodic() { 
  3.  return period != 0; 

 這個方法主要是用來判斷當前任務是否是周期性任務。這里只要判斷運行任務的執行周期不等于0就能確定為周期性任務了。因為無論period的值是大于0還是小于0,當前任務都是周期性任務。

setNextRunTime方法

setNextRunTime方法的作用主要是設置當前任務下次執行的時間,源碼如下所示:

  1. private void setNextRunTime() { 
  2.  long p = period; 
  3.  //固定頻率,上次執行任務的時間加上任務的執行周期 
  4.  if (p > 0) 
  5.   time += p; 
  6.  //相對固定的延遲執行,當前系統時間加上任務的執行周期 
  7.  else 
  8.   time = triggerTime(-p); 

 這里再一次證明了使用isPeriodic方法判斷當前任務是否為周期性任務時,只要判斷period的值是否不等于0就可以了。

  • 因為如果當前任務時固定頻率執行的周期性任務,會將周期period當作正數來處理;
  • 如果是相對固定的延遲執行當前任務,則會將周期period當作負數來處理。

這里我們看到在setNextRunTime方法中,調用了ScheduledThreadPoolExecutor類的triggerTime方法。接下來我們看下triggerTime方法的源碼。

ScheduledThreadPoolExecutor類的triggerTime方法

triggerTime方法用于獲取延遲隊列中的任務下一次執行的具體時間。源碼如下所示。

  1. private long triggerTime(long delay, TimeUnit unit) { 
  2.  return triggerTime(unit.toNanos((delay < 0) ? 0 : delay)); 
  3.  
  4. long triggerTime(long delay) { 
  5.  return now() + 
  6.   ((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay)); 

 這兩個triggerTime方法的代碼比較簡單,就是獲取下一次執行任務的具體時間。有一點需要注意的是:delay < (Long.MAX_VALUE >> 1判斷delay的值是否小于Long.MAX_VALUE的一半,如果小于Long.MAX_VALUE值的一半,則直接返回delay,否則需要處理溢出的情況。

我們看到在triggerTime方法中處理防止溢出的邏輯使用了ScheduledThreadPoolExecutor類的overflowFree方法,接下來,我們就看看ScheduledThreadPoolExecutor類的overflowFree方法的實現。

ScheduledThreadPoolExecutor類的overflowFree方法

overflowFree方法的源代碼如下所示:

  1. private long overflowFree(long delay) { 
  2.  //獲取隊列中的節點 
  3.  Delayed head = (Delayed) super.getQueue().peek(); 
  4.  //獲取的節點不為空,則進行后續處理 
  5.  if (head != null) { 
  6.   //從隊列節點中獲取延遲時間 
  7.   long headDelay = head.getDelay(NANOSECONDS); 
  8.   //如果從隊列中獲取的延遲時間小于0,并且傳遞的delay 
  9.   //值減去從隊列節點中獲取延遲時間小于0 
  10.   if (headDelay < 0 && (delay - headDelay < 0)) 
  11.    //將delay的值設置為Long.MAX_VALUE + headDelay 
  12.    delay = Long.MAX_VALUE + headDelay; 
  13.  } 
  14.  //返回延遲時間 
  15.  return delay; 

 通過對overflowFree方法的源碼分析,可以看出overflowFree方法本質上就是為了限制隊列中的所有節點的延遲時間在Long.MAX_VALUE值之內,防止在compareTo方法中溢出。

cancel方法

cancel方法的作用主要是取消當前任務的執行,源碼如下所示:

  1. public boolean cancel(boolean mayInterruptIfRunning) { 
  2.  //取消任務,返回任務是否取消的標識 
  3.  boolean cancelled = super.cancel(mayInterruptIfRunning); 
  4.  //如果任務已經取消 
  5.  //并且需要將任務從延遲隊列中刪除 
  6.  //并且任務在延遲隊列中的索引大于或者等于0 
  7.  if (cancelled && removeOnCancel && heapIndex >= 0) 
  8.   //將當前任務從延遲隊列中刪除 
  9.   remove(this); 
  10.  //返回是否成功取消任務的標識 
  11.  return cancelled; 

 這段代碼理解起來相對比較簡單,首先調用取消任務的方法,并返回任務是否已經取消的標識。如果任務已經取消,并且需要移除任務,同時,任務在延遲隊列中的索引大于或者等于0,則將當前任務從延遲隊列中移除。最后返回任務是否成功取消的標識。

run方法

run方法可以說是ScheduledFutureTask類的核心方法,是對Runnable接口的實現,源碼如下所示:

  1. public void run() { 
  2.  //當前任務是否是周期性任務 
  3.  boolean periodic = isPeriodic(); 
  4.  //線程池當前運行狀態下不能執行周期性任務 
  5.  if (!canRunInCurrentRunState(periodic)) 
  6.   //取消任務的執行 
  7.   cancel(false); 
  8.  //如果不是周期性任務 
  9.  else if (!periodic) 
  10.   //則直接調用FutureTask類的run方法執行任務 
  11.   ScheduledFutureTask.super.run(); 
  12.  //如果是周期性任務,則調用FutureTask類的runAndReset方法執行任務 
  13.  //如果任務執行成功 
  14.  else if (ScheduledFutureTask.super.runAndReset()) { 
  15.   //設置下次執行任務的時間 
  16.   setNextRunTime(); 
  17.   //重復執行任務 
  18.   reExecutePeriodic(outerTask); 
  19.  } 

 整理一下方法的邏輯:

  1. 首先判斷當前任務是否是周期性任務。如果線程池當前運行狀態下不能執行周期性任務,則取消任務的執行,否則執行步驟2;
  2. 如果當前任務不是周期性任務,則直接調用FutureTask類的run方法執行任務,會設置執行結果,然后直接返回,否則執行步驟3;
  3. 如果當前任務是周期性任務,則調用FutureTask類的runAndReset方法執行任務,不會設置執行結果,然后直接返回,否則執行步驟4;
  4. 如果任務執行成功,則設置下次執行任務的時間,同時,將任務設置為重復執行。

這里,調用了FutureTask類的run方法和runAndReset方法,并且調用了ScheduledThreadPoolExecutor類的reExecutePeriodic方法。接下來,我們分別看下這些方法的實現。

FutureTask類的run方法

FutureTask類的run方法源碼如下所示:

  1. public void run() { 
  2.     //狀態如果不是NEW,說明任務或者已經執行過,或者已經被取消,直接返回 
  3.     //狀態如果是NEW,則嘗試把當前執行線程保存在runner字段中 
  4.     //如果賦值失敗則直接返回 
  5.     if (state != NEW || 
  6.         !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread())) 
  7.         return
  8.     try { 
  9.         Callable<V> c = callable; 
  10.         if (c != null && state == NEW) { 
  11.             V result; 
  12.             boolean ran; 
  13.             try { 
  14.                 //執行任務 
  15.                 result = c.call(); 
  16.                 ran = true
  17.             } catch (Throwable ex) { 
  18.                 result = null
  19.                 ran = false
  20.                 //任務異常 
  21.                 setException(ex); 
  22.             } 
  23.             if (ran) 
  24.                 //任務正常執行完畢 
  25.                 set(result); 
  26.         } 
  27.     } finally { 
  28.  
  29.         runner = null
  30.         int s = state; 
  31.         //如果任務被中斷,執行中斷處理 
  32.         if (s >= INTERRUPTING) 
  33.             handlePossibleCancellationInterrupt(s); 
  34.     } 

 代碼的整體邏輯為:

  • 判斷當前任務的state是否等于NEW,如果不為NEW則說明任務或者已經執行過,或者已經被取消,直接返回;
  • 如果狀態為NEW則接著會通過unsafe類把任務執行線程引用CAS的保存在runner字段中,如果保存失敗,則直接返回;
  • 執行任務;如果任務執行發生異常,則調用setException()方法保存異常信息。

FutureTask類的runAndReset方法

方法的源碼如下所示:

  1. protected boolean runAndReset() { 
  2.  if (state != NEW || 
  3.   !UNSAFE.compareAndSwapObject(this, runnerOffset, 
  4.           null, Thread.currentThread())) 
  5.   return false
  6.  boolean ran = false
  7.  int s = state; 
  8.  try { 
  9.   Callable<V> c = callable; 
  10.   if (c != null && s == NEW) { 
  11.    try { 
  12.     c.call(); // don't set result 
  13.     ran = true
  14.    } catch (Throwable ex) { 
  15.     setException(ex); 
  16.    } 
  17.   } 
  18.  } finally { 
  19.   // runner must be non-null until state is settled to 
  20.   // prevent concurrent calls to run() 
  21.   runner = null
  22.   // state must be re-read after nulling runner to prevent 
  23.   // leaked interrupts 
  24.   s = state; 
  25.   if (s >= INTERRUPTING) 
  26.    handlePossibleCancellationInterrupt(s); 
  27.  } 
  28.  return ran && s == NEW; 

 FutureTask類的runAndReset方法與run方法的邏輯基本相同,只是runAndReset方法會重置當前任務的執行狀態。

ScheduledThreadPoolExecutor類的reExecutePeriodic方法

reExecutePeriodic重復執行任務方法,源代碼如下所示:

  1. void reExecutePeriodic(RunnableScheduledFuture<?> task) { 
  2.  //線程池當前狀態下能夠執行任務 
  3.  if (canRunInCurrentRunState(true)) { 
  4.   //與ThreadPoolExecutor不同,這里直接把任務加入延遲隊列 
  5.         super.getQueue().add(task);//使用用的DelayedWorkQueue 
  6.   //線程池當前狀態下不能執行任務,并且成功移除任務 
  7.   if (!canRunInCurrentRunState(true) && remove(task)) 
  8.    //取消任務 
  9.    task.cancel(false); 
  10.   else 
  11.    //這里是增加一個worker線程,避免提交的任務沒有worker去執行 
  12.             //原因就是該類沒有像ThreadPoolExecutor一樣,woker滿了才放入隊列   
  13.    ensurePrestart(); 
  14.  } 

 總體來說reExecutePeriodic方法的邏輯比較簡單,需要注意的是:調用reExecutePeriodic方法的時候已經執行過一次任務,所以,并不會觸發線程池的拒絕策略;傳入reExecutePeriodic方法的任務一定是周期性的任務。

DelayedWorkQueue

ScheduledThreadPoolExecutor之所以要自己實現阻塞的工作隊列,是因為 ScheduleThreadPoolExecutor 要求的工作隊列有些特殊。

DelayedWorkQueue是一個基于堆的數據結構,類似于DelayQueue和PriorityQueue。在執行定時任務的時候,每個任務的執行時間都不同,所以DelayedWorkQueue的工作就是按照執行時間的升序來排列,執行時間距離當前時間越近的任務在隊列的前面(注意:這里的順序并不是絕對的,堆中的排序只保證了子節點的下次執行時間要比父節點的下次執行時間要大,而葉子節點之間并不一定是順序的)。

堆結構如下圖:

 可見,DelayedWorkQueue是一個基于最小堆結構的隊列。堆結構可以使用數組表示,可以轉換成如下的數組:

并發編程之定時任務&定時線程池原理解析

 在這種結構中,可以發現有如下特性: 假設“第一個元素” 在數組中的索引為 0 的話,則父結點和子結點的位置關系如下:

  • 索引為 的左孩子的索引是 (2∗i+1);
  • 索引為 的右孩子的索引是 (2∗i+2);
  • 索引為 的父結點的索引是 floor((i−1)/2);

為什么要使用DelayedWorkQueue呢?

  • 定時任務執行時需要取出最近要執行的任務,所以任務在隊列中每次出隊時一定要是當前隊列中執行時間最靠前的,所以自然要使用優先級隊列。
  • DelayedWorkQueue是一個優先級隊列,它可以保證每次出隊的任務都是當前隊列中執行時間最靠前的,由于它是基于堆結構的隊列,堆結構在執行插入和刪除操作時的最壞時間復雜度是 O(logN)。

因為前面講阻塞隊列實現的時候,已經對DelayedWorkQueue進行了說明,更多內容請查看《阻塞隊列 — DelayedWorkQueue源碼分析》

總結

  1. 與Timer執行定時任務比較,相比Timer,ScheduledThreadPoolExecutor有說明優點?(文章前面分析過)
  2. ScheduledThreadPoolExecutor繼承自ThreadPoolExecutor,所以它也是一個線程池,也有 coorPoolSize 和 workQueue,但是 ScheduledThreadPoolExecutor特殊的地方在于,自己實現了優先工作隊列 DelayedWorkQueue ;
  3. ScheduledThreadPoolExecutor 實現了 ScheduledExecutorService,所以就有了任務調度的方法,如 schedule 、 scheduleAtFixedRate 、 scheduleWithFixedDelay ,同時注意他們之間的區別;
  4. 內部類 ScheduledFutureTask 繼承者FutureTask,實現了任務的異步執行并且可以獲取返回結果。同時實現了Delayed接口,可以通過getDelay方法獲取將要執行的時間間隔;
  5. 周期任務的執行其實是調用了FutureTask的 runAndReset 方法,每次執行完不設置結果和狀態。
  6. DelayedWorkQueue的數據結構,它是一個基于最小堆結構的優先隊列,并且每次出隊時能夠保證取出的任務是當前隊列中下次執行時間最小的任務。同時注意一下優先隊列中堆的順序,堆中的順序并不是絕對的,但要保證子節點的值要比父節點的值要大,這樣就不會影響出隊的順序。

總體來說,ScheduedThreadPoolExecutor的重點是要理解下次執行時間的計算,以及優先隊列的出隊、入隊和刪除的過程,這兩個是理解ScheduedThreadPoolExecutor的關鍵。

PS:以上代碼提交在 Github :

https://github.com/Niuh-Study/niuh-juc-final.git

 

責任編輯:姜華 來源: 今日頭條
相關推薦

2020-12-08 08:53:53

編程ThreadPoolE線程池

2024-02-28 09:54:07

線程池配置

2022-03-28 08:31:29

線程池定時任務

2020-12-21 07:31:23

實現單機JDK

2024-12-27 08:24:55

2017-01-10 13:39:57

Python線程池進程池

2023-01-16 08:49:20

RocketMQ定時任務源代

2009-10-28 10:05:29

Ubuntucrontab定時任務

2012-02-07 13:31:14

SpringJava

2010-03-10 15:47:58

crontab定時任務

2022-11-09 09:01:08

并發編程線程池

2016-10-21 11:04:07

JavaScript異步編程原理解析

2024-11-04 16:01:01

2010-01-07 13:38:41

Linux定時任務

2024-05-13 09:49:30

.NETQuartz庫Cron表達式

2023-11-07 07:47:35

Topic線程PUSH

2023-12-19 08:09:06

Python定時任務Cron表達式

2021-12-16 14:25:03

Linux定時任務

2022-08-15 15:43:29

Linuxcron

2025-09-08 00:00:01

點贊
收藏

51CTO技術棧公眾號

亚洲午夜一级| 狠狠久久伊人中文字幕| 成人av网站在线| 欧洲日本亚洲国产区| 在线免费看黄视频| 粉嫩91精品久久久久久久99蜜桃| 日韩毛片精品高清免费| 国产另类自拍| 亚洲天堂久久久久| 亚洲国产高清一区| 在线日韩中文字幕| 亚洲av无一区二区三区久久| 亚洲天堂av在线| 国产精品国产自产拍高清av| 国产在线观看一区| 亚洲怡红院av| 亚洲激情网址| 精品国产拍在线观看| 欲求不满的岳中文字幕| 欧美久久久网站| 偷窥国产亚洲免费视频| 亚洲图片都市激情| 少妇性bbb搡bbb爽爽爽欧美| 久久爱www久久做| 亚洲97在线观看| 欧美乱大交做爰xxxⅹ小说| 超碰精品在线观看| 欧美区一区二区三区| 国产 日韩 欧美在线| a√资源在线| 91理论电影在线观看| 亚洲精品免费av| 中文字幕在线播| 好吊视频一区二区三区四区| 色哟哟亚洲精品一区二区| 久久精品综合视频| 爱爱精品视频| 日韩欧美视频在线| 涩涩网站在线看| 韩日精品一区| 欧洲精品一区二区| www.av毛片| 日本在线视频网址| 亚洲精品日日夜夜| 国产精品美女在线播放| 国产视频在线看| 久久久久久久久久久久久久久99 | 欧美一区二区福利| 神马一区二区三区| 国产不卡在线视频| 97av影视网在线观看| 国产精品久久777777换脸| 日韩av中文在线观看| 日本国产一区二区三区| 久久久精品免费看| 国产精品日韩| 26uuu另类亚洲欧美日本老年| 国产亚洲精品成人| 精久久久久久| 久久久伊人日本| 久久综合色综合| 黄色免费成人| 性欧美亚洲xxxx乳在线观看| 日本免费观看视| 一区二区三区福利| 538国产精品一区二区在线| 国产一级精品视频| 亚洲欧美日韩视频二区| 欧美在线性爱视频| www.欧美色| 日本不卡一二三区黄网| 国产精品高潮呻吟久久av无限| 天堂免费在线视频| 美国av一区二区| 成人啪啪免费看| 精品人妻伦一区二区三区久久| 国产精品一区不卡| 国产一区免费在线观看| 日中文字幕在线| 欧美激情综合在线| 特级毛片在线免费观看| 午夜小视频福利在线观看| 亚洲图片欧美一区| 激情六月丁香婷婷| 亚洲精品成a人ⅴ香蕉片| 69堂成人精品免费视频| 男人的天堂免费| 五月综合久久| 色吧影院999| 欧美日韩在线视频免费播放| av不卡在线| 国产精品人成电影在线观看| www.xxxx国产| 国产亚洲成年网址在线观看| 中文字幕在线乱| 91美女精品| 欧美视频中文一区二区三区在线观看| 在线a免费观看| 人妖一区二区三区| 日韩中文字幕视频在线| 日韩av女优在线观看| 青青草97国产精品免费观看 | 国产剧情在线视频| 韩日av一区二区| 精品欧美国产| 久草免费在线观看| 第一福利永久视频精品| 日韩欧美亚洲另类| 亚洲婷婷影院| 蜜臀久久99精品久久久久久宅男| 国产原创视频在线| 国产一区二区三区黄视频 | 精品国产一区二区三区噜噜噜| 欧美成aaa人片在线观看蜜臀| 日本视频在线观看免费| 国产成人免费高清| 午夜一区二区三视频在线观看| heyzo高清中文字幕在线| 欧美三片在线视频观看| 久久人妻一区二区| 欧美黄色一区| 国产欧美精品一区二区三区-老狼 国产欧美精品一区二区三区介绍 国产欧美精品一区二区 | 亚洲欧美中文日韩在线| 免费人成在线观看| 美国一区二区三区在线播放| 久久久久久九九九九| 污视频网站在线免费| 欧美日韩国产成人在线91| xxxx黄色片| 欧美网站在线| 亚洲一区二区中文字幕| 在线观看免费黄视频| 色天使色偷偷av一区二区| 蜜臀av粉嫩av懂色av| 综合天堂av久久久久久久| 国产欧美一区二区三区久久| 神马精品久久| 欧美三级免费观看| 欧美双性人妖o0| 国产精品chinese| 91亚洲国产成人精品性色| 77777影视视频在线观看| 在线国产亚洲欧美| 日韩毛片无码永久免费看| 亚洲尤物影院| 久久影视中文粉嫩av| 黄色在线观看www| 亚洲第一av网站| 国产一级aa大片毛片| 国产精品一二二区| 4444在线观看| 日韩三级不卡| 九九精品在线观看| www.热久久| 亚洲影视资源网| 国内自拍偷拍视频| 亚洲午夜在线| 国内一区二区三区在线视频| 高清在线视频不卡| 亚洲第一色在线| 日韩精品一区二区三| jlzzjlzz国产精品久久| 777精品久无码人妻蜜桃| 日韩高清三区| 国产97在线观看| av大片在线观看| 51久久夜色精品国产麻豆| 三级在线观看免费大全| 国产电影精品久久禁18| 岛国大片在线播放| 人人网欧美视频| 国产精品丝袜一区二区三区| 黄色网址视频在线观看| 精品剧情在线观看| 免费观看一区二区三区毛片| 国产日韩欧美高清| 污污视频在线免费| 最新日韩欧美| 日韩女优中文字幕| 免费精品一区| 91干在线观看| 婷婷五月在线视频| 精品国产污污免费网站入口| 啦啦啦免费高清视频在线观看| 国产亚洲综合色| 樱花草www在线| 99视频+国产日韩欧美| 日本视频一区二区在线观看| 日本黄色成人| 高清视频欧美一级| av在线天堂播放| 精品日韩成人av| 无码视频一区二区三区| 亚洲欧美另类小说视频| 欧美在线一级片| 麻豆91精品91久久久的内涵| 美女黄色免费看| 秋霞欧美视频| 国产精品日韩欧美一区二区| 国产精品videossex撒尿| 九九久久久久99精品| 久久久久久久影视| 欧美大片在线观看一区二区| 精品久久久久久久久久久国产字幕| 亚洲日本丝袜连裤袜办公室| 国产呦小j女精品视频| 国内久久婷婷综合| 那种视频在线观看| 国产精品va| 一本一生久久a久久精品综合蜜| 卡通动漫国产精品| 91欧美精品成人综合在线观看| 国产乱码精品一区二三赶尸艳谈| 日韩一区二区三区xxxx| 日韩美女一级视频| 精品久久久久久久久久久久包黑料 | 免费观看黄色av| 欧美日韩在线电影| 亚洲欧美另类在线视频| 一个色在线综合| 国产男女猛烈无遮挡在线喷水| 久久久久久久久久电影| 一级欧美一级日韩片| 国产精品一区二区在线看| 中文字幕第36页| 久久不射网站| 蜜臀av无码一区二区三区| 欧美精品不卡| av不卡在线免费观看| 欧洲三级视频| 欧美精品七区| 久久99偷拍| 国产精品久久久久久久小唯西川 | 欧美四级电影网| 天堂网中文字幕| 精品国产91乱高清在线观看| 精品人妻在线播放| 一区二区三区毛片| 精品国产精品国产精品| 国产精品国产三级国产专播品爱网 | 日韩一级特黄毛片| 欧美日韩精品| 毛片av在线播放| 欧美全黄视频| 久久综合久久久久| 尤物在线精品| 妞干网在线视频观看| 亚洲精品四区| 97国产在线播放| 国产精品嫩草99av在线| 日本www在线播放| 性一交一乱一区二区洋洋av| 草草久久久无码国产专区| 亚洲国内欧美| 日韩中文字幕在线视频观看| 日韩亚洲精品在线| 99爱视频在线| 久久综合五月| 日韩中文字幕免费在线| 三级不卡在线观看| 黄色在线视频网| 六月丁香综合在线视频| 国产精欧美一区二区三区白种人| 久久激情五月婷婷| 亚洲精品一二三四| 成人av午夜影院| 成年人在线观看av| 中文字幕欧美激情| 成人在线观看小视频| 亚洲精品美国一| 国产无套在线观看| 色香蕉久久蜜桃| 亚洲性生活大片| 日韩一区二区电影在线| 成人午夜福利视频| 亚洲免费影视第一页| a黄色在线观看| 欧美日韩ab片| 亚洲国产福利| 成人春色激情网| 亚洲一区二区三区在线免费| 久久国产精品久久精品国产| 欧美中文字幕一区二区| 大陆极品少妇内射aaaaaa| 日本一卡二卡在线| 精品午夜久久福利影院| 97人妻精品一区二区三区免费| 91色porny在线视频| 国产小视频你懂的| 亚洲成人久久影院| 久久久久精彩视频| 欧美大片一区二区| 欧美黄色小说| 不卡av电影院| 成人勉费视频| 99久热re在线精品视频| 国内精品伊人久久久| 国产精品无码免费专区午夜| 日韩精品亚洲专区| 一二三区视频在线观看| 国产偷v国产偷v亚洲高清| 久久久久久蜜桃| 欧洲日韩一区二区三区| 黄色av网址在线| 色一区av在线| 中文在线中文资源| 亚洲一区二区三区香蕉| 精品国精品国产自在久国产应用 | 成人做爰www免费看视频网站| 久久久久观看| 欧美少妇一区二区三区| 日日夜夜精品免费视频| 国产在线观看免费播放| 中文字幕av一区二区三区| 欧美成人精品欧美一级乱黄| 51久久夜色精品国产麻豆| 国产三级在线看| 欧美亚洲成人网| 一区二区三区四区高清视频| 翔田千里亚洲一二三区| 免费永久网站黄欧美| 中文字幕第九页| 亚洲嫩草精品久久| 中文字幕人成人乱码亚洲电影| 精品亚洲aⅴ在线观看| 久色国产在线| 亚洲精品免费av| 99久久夜色精品国产亚洲96 | 亚洲高清在线播放| 日韩精品色哟哟| 精品少妇一区二区三区免费观| 亚洲1区2区3区视频| www香蕉视频| 精品国产网站地址| 久久精品超碰| 少妇特黄a一区二区三区| 久久激情久久| 国产全是老熟女太爽了| 欧美视频中文字幕在线| 色偷偷在线观看| 久久久久久久999精品视频| 中文字幕一区日韩精品| 屁屁影院ccyy国产第一页| 国产乱码精品一区二区三| 97在线观看视频免费| 欧美日本精品一区二区三区| 自拍视频在线免费观看| 国产日韩中文字幕| 日韩综合网站| 另类小说色综合| 国产精品初高中害羞小美女文| 久久久999久久久| 亚洲午夜未删减在线观看 | 成人午夜小视频| 91精品久久久久久久久久不卡| 在线观看免费的av| 成人欧美一区二区三区黑人麻豆| 91高潮大合集爽到抽搐| 久久这里只有精品视频首页| 精品国产三级| 成年在线观看视频| 成人高清免费观看| 五月婷婷中文字幕| 亚洲少妇激情视频| 欧美不卡高清一区二区三区| 亚洲不卡1区| 国产在线国偷精品免费看| 老湿机69福利| 亚洲国产小视频| 久久91导航| 成人在线观看www| 国产激情91久久精品导航| 久久精品www人人爽人人| 亚洲福利精品在线| 欧美magnet| 欧美性视频在线播放| 国产 日韩 欧美大片| 日本特级黄色片| 色偷偷91综合久久噜噜| 日韩免费成人| 国产一区二区在线视频播放| 国产亚洲一区二区三区四区| 在线观看免费黄色小视频| 九九热这里只有精品6| 首页亚洲中字| 欧美激情第3页| 午夜婷婷国产麻豆精品| 久久综合九色综合久| 亚洲自拍偷拍一区| 亚洲综合日本| 一区二区三区影视| 精品久久久久久久久久久院品网 | 香蕉国产精品| 国产一级二级视频| 欧美日韩极品在线观看一区| 日本aa在线| 天堂一区二区三区| 成人黄色网址在线观看| 波多野结衣午夜| 欧美极品少妇xxxxⅹ免费视频 |