【高併發】深度解析ScheduledThreadPoolExecutor類的源代碼

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"大家好,我是冰河~~","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在【高併發專題】的專欄中,我們深度分析了ThreadPoolExecutor類的源代碼,而ScheduledThreadPoolExecutor類是ThreadPoolExecutor類的子類。今天我們就來一起手撕ScheduledThreadPoolExecutor類的源代碼。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"構造方法","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們先來看下ScheduledThreadPoolExecutor的構造方法,源代碼如下所示。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public ScheduledThreadPoolExecutor(int corePoolSize) {\n super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue());\n}\n\npublic ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory) {\n super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,\n new DelayedWorkQueue(), threadFactory);\n}\n\npublic ScheduledThreadPoolExecutor(int corePoolSize, RejectedExecutionHandler handler) {\n super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,\n new DelayedWorkQueue(), handler);\n}\n\npublic ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory, RejectedExecutionHandler handler) {\n super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,\n new DelayedWorkQueue(), threadFactory, handler);\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從代碼結構上來看,ScheduledThreadPoolExecutor類是ThreadPoolExecutor類的子類,ScheduledThreadPoolExecutor類的構造方法實際上調用的是ThreadPoolExecutor類的構造方法。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"schedule方法","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接下來,我們看一下ScheduledThreadPoolExecutor類的schedule方法,源代碼如下所示。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public ScheduledFuture> schedule(Runnable command, long delay, TimeUnit unit) {\n //如果傳遞的Runnable對象和TimeUnit時間單位爲空\n //拋出空指針異常\n if (command == null || unit == null)\n throw new NullPointerException();\n //封裝任務對象,在decorateTask方法中直接返回ScheduledFutureTask對象\n RunnableScheduledFuture> t = decorateTask(command, new ScheduledFutureTask(command, null, triggerTime(delay, unit)));\n //執行延時任務\n delayedExecute(t);\n //返回任務\n return t;\n}\n\npublic ScheduledFuture schedule(Callable callable, long delay, TimeUnit unit) \n //如果傳遞的Callable對象和TimeUnit時間單位爲空\n //拋出空指針異常\n if (callable == null || unit == null)\n throw new NullPointerException();\n //封裝任務對象,在decorateTask方法中直接返回ScheduledFutureTask對象\n RunnableScheduledFuture t = decorateTask(callable,\n new ScheduledFutureTask(callable, triggerTime(delay, unit)));\n //執行延時任務\n delayedExecute(t);\n //返回任務\n return t;\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從源代碼可以看出,ScheduledThreadPoolExecutor類提供了兩個重載的schedule方法,兩個schedule方法的第一個參數不同。可以傳遞Runnable接口對象,也可以傳遞Callable接口對象。在方法內部,會將Runnable接口對象和Callable接口對象封裝成RunnableScheduledFuture對象,本質上就是封裝成ScheduledFutureTask對象。並通過delayedExecute方法來執行延時任務。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在源代碼中,我們看到兩個schedule都調用了decorateTask方法,接下來,我們就看看decorateTask方法。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"decorateTask方法","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"decorateTask方法源代碼如下所示。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"protected RunnableScheduledFuture decorateTask(Runnable runnable, RunnableScheduledFuture task) {\n return task;\n}\n\nprotected RunnableScheduledFuture decorateTask(Callable callable, RunnableScheduledFuture task) {\n return task;\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通過源碼可以看出decorateTask方法的實現比較簡單,接收一個Runnable接口對象或者Callable接口對象和封裝的RunnableScheduledFuture任務,兩個方法都是將RunnableScheduledFuture任務直接返回。在ScheduledThreadPoolExecutor類的子類中可以重寫這兩個方法。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接下來,我們繼續看下scheduleAtFixedRate方法。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"scheduleAtFixedRate方法","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"scheduleAtFixedRate方法源代碼如下所示。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public ScheduledFuture> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {\n //傳入的Runnable對象和TimeUnit爲空,則拋出空指針異常\n if (command == null || unit == null)\n throw new NullPointerException();\n //如果執行週期period傳入的數值小於或者等於0\n //拋出非法參數異常\n if (period <= 0)\n throw new IllegalArgumentException();\n //將Runnable對象封裝成ScheduledFutureTask任務,\n //並設置執行週期\n ScheduledFutureTask sft =\n new ScheduledFutureTask(command, null, triggerTime(initialDelay, unit), unit.toNanos(period));\n //調用decorateTask方法,本質上還是直接返回ScheduledFutureTask對象\n RunnableScheduledFuture t = decorateTask(command, sft);\n //設置執行的任務\n sft.outerTask = t;\n //執行延時任務\n delayedExecute(t);\n //返回執行的任務\n return t;\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通過源碼可以看出,scheduleAtFixedRate方法將傳遞的Runnable對象封裝成ScheduledFutureTask任務對象,並設置了執行週期,下一次的執行時間相對於上一次的執行時間來說,加上了period時長,時長的具體單位由TimeUnit決定。採用固定的頻率來執行定時任務。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"ScheduledThreadPoolExecutor類中另一個定時調度任務的方法是scheduleWithFixedDelay方法,接下來,我們就一起看看scheduleWithFixedDelay方法。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"scheduleWithFixedDelay方法","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"scheduleWithFixedDelay方法的源代碼如下所示。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public ScheduledFuture> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {\n //傳入的Runnable對象和TimeUnit爲空,則拋出空指針異常\n if (command == null || unit == null)\n throw new NullPointerException();\n //任務延時時長小於或者等於0,則拋出非法參數異常\n if (delay <= 0)\n throw new IllegalArgumentException();\n //將Runnable對象封裝成ScheduledFutureTask任務\n //並設置固定的執行週期來執行任務\n ScheduledFutureTask sft =\n new ScheduledFutureTask(command, null,triggerTime(initialDelay, unit), unit.toNanos(-delay));\n //調用decorateTask方法,本質上直接返回ScheduledFutureTask任務\n RunnableScheduledFuture t = decorateTask(command, sft);\n //設置執行的任務\n sft.outerTask = t;\n //執行延時任務\n delayedExecute(t);\n //返回任務\n return t;\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從scheduleWithFixedDelay方法的源代碼,我們可以看出在將Runnable對象封裝成ScheduledFutureTask時,設置了執行週期,但是此時設置的執行週期與scheduleAtFixedRate方法設置的執行週期不同。此時設置的執行週期規則爲:下一次任務執行的時間是上一次任務完成的時間加上delay時長,時長單位由TimeUnit決定。也就是說,具體的執行時間不是固定的,但是執行的週期是固定的,整體採用的是相對固定的延遲來執行定時任務。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果大家細心的話,會發現在scheduleWithFixedDelay方法中設置執行週期時,傳遞的delay值爲負數,如下所示。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"ScheduledFutureTask sft =\n new ScheduledFutureTask(command, null, triggerTime(initialDelay, unit), unit.toNanos(-delay));\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏的負數表示的是相對固定的延遲。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在ScheduledFutureTask類中,存在一個setNextRunTime方法,這個方法會在run方法執行完任務後調用,這個方法更能體現scheduleAtFixedRate方法和scheduleWithFixedDelay方法的不同,setNextRunTime方法的源碼如下所示。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"private void setNextRunTime() {\n //距離下次執行任務的時長\n long p = period;\n //固定頻率執行,\n //上次執行任務的時間\n //加上任務的執行週期\n if (p > 0)\n time += p;\n //相對固定的延遲\n //使用的是系統當前時間\n //加上任務的執行週期\n else\n time = triggerTime(-p);\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在setNextRunTime方法中通過對下次執行任務的時長進行判斷來確定是固定頻率執行還是相對固定的延遲。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"triggerTime方法","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在ScheduledThreadPoolExecutor類中提供了兩個triggerTime方法,用於獲取下一次執行任務的具體時間。triggerTime方法的源碼如下所示。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"private long triggerTime(long delay, TimeUnit unit) {\n return triggerTime(unit.toNanos((delay < 0) ? 0 : delay));\n}\n\nlong triggerTime(long delay) {\n return now() +\n ((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay));\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這兩個triggerTime方法的代碼比較簡單,就是獲取下一次執行任務的具體時間。有一點需要注意的是:delay < (Long.MAX_VALUE >> 1判斷delay的值是否小於Long.MAX_VALUE的一半,如果小於Long.MAX_VALUE值的一半,則直接返回delay,否則需要處理溢出的情況。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們看到在triggerTime方法中處理防止溢出的邏輯使用了overflowFree方法,接下來,我們就看看overflowFree方法的實現。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"overflowFree方法","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"overflowFree方法的源代碼如下所示。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"private long overflowFree(long delay) {\n //獲取隊列中的節點\n Delayed head = (Delayed) super.getQueue().peek();\n //獲取的節點不爲空,則進行後續處理\n if (head != null) {\n //從隊列節點中獲取延遲時間\n long headDelay = head.getDelay(NANOSECONDS);\n //如果從隊列中獲取的延遲時間小於0,並且傳遞的delay\n //值減去從隊列節點中獲取延遲時間小於0\n if (headDelay < 0 && (delay - headDelay < 0))\n //將delay的值設置爲Long.MAX_VALUE + headDelay\n delay = Long.MAX_VALUE + headDelay;\n }\n //返回延遲時間\n return delay;\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通過對overflowFree方法的源碼分析,可以看出overflowFree方法本質上就是爲了限制隊列中的所有節點的延遲時間在Long.MAX_VALUE值之內,防止在ScheduledFutureTask類中的compareTo方法中溢出。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"ScheduledFutureTask類中的compareTo方法的源碼如下所示。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public int compareTo(Delayed other) {\n if (other == this) // compare zero if same object\n return 0;\n if (other instanceof ScheduledFutureTask) {\n ScheduledFutureTask> x = (ScheduledFutureTask>)other;\n long diff = time - x.time;\n if (diff < 0)\n return -1;\n else if (diff > 0)\n return 1;\n else if (sequenceNumber < x.sequenceNumber)\n return -1;\n else\n return 1;\n }\n long diff = getDelay(NANOSECONDS) - other.getDelay(NANOSECONDS);\n return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"compareTo方法的主要作用就是對各延遲任務進行排序,距離下次執行時間靠前的任務就排在前面。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"delayedExecute方法","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"delayedExecute方法是ScheduledThreadPoolExecutor類中延遲執行任務的方法,源代碼如下所示。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"private void delayedExecute(RunnableScheduledFuture> task) {\n //如果當前線程池已經關閉\n //則執行線程池的拒絕策略\n if (isShutdown())\n reject(task);\n //線程池沒有關閉\n else {\n //將任務添加到阻塞隊列中\n super.getQueue().add(task);\n //如果當前線程池是SHUTDOWN狀態\n //並且當前線程池狀態下不能執行任務\n //並且成功從阻塞隊列中移除任務\n if (isShutdown() &&\n !canRunInCurrentRunState(task.isPeriodic()) &&\n remove(task))\n //取消任務的執行,但不會中斷執行中的任務\n task.cancel(false);\n else\n //調用ThreadPoolExecutor類中的ensurePrestart()方法\n ensurePrestart();\n }\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以看到在delayedExecute方法內部調用了canRunInCurrentRunState方法,canRunInCurrentRunState方法的源碼實現如下所示。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"boolean canRunInCurrentRunState(boolean periodic) {\n return isRunningOrShutdown(periodic ? continueExistingPeriodicTasksAfterShutdown : executeExistingDelayedTasksAfterShutdown);\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以看到canRunInCurrentRunState方法的邏輯比較簡單,就是判斷線程池當前狀態下能夠執行任務。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"另外,在delayedExecute方法內部還調用了ThreadPoolExecutor類中的ensurePrestart()方法,接下來,我們看下ThreadPoolExecutor類中的ensurePrestart()方法的實現,如下所示。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"void ensurePrestart() {\n int wc = workerCountOf(ctl.get());\n if (wc < corePoolSize)\n addWorker(null, true);\n else if (wc == 0)\n addWorker(null, false);\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在ThreadPoolExecutor類中的ensurePrestart()方法中,首先獲取當前線程池中線程的數量,如果線程數量小於corePoolSize則調用addWorker方法傳遞null和true,如果線程數量爲0,則調用addWorker方法傳遞null和false。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"關於addWork()方法的源碼解析,大家可以參考【高併發專題】中的《","attrs":{}},{"type":"link","attrs":{"href":"https://blog.csdn.net/l1028386804/article/details/104480010","title":"","type":null},"content":[{"type":"text","text":"高併發之——通過ThreadPoolExecutor類的源碼深度解析線程池執行任務的核心流程","attrs":{}}]},{"type":"text","text":"》一文,這裏,不再贅述。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"reExecutePeriodic方法","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"reExecutePeriodic方法的源代碼如下所示。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"void reExecutePeriodic(RunnableScheduledFuture> task) {\n //線程池當前狀態下能夠執行任務\n if (canRunInCurrentRunState(true)) {\n //將任務放入隊列\n super.getQueue().add(task);\n //線程池當前狀態下不能執行任務,並且成功移除任務\n if (!canRunInCurrentRunState(true) && remove(task))\n //取消任務\n task.cancel(false);\n else\n //調用ThreadPoolExecutor類的ensurePrestart()方法\n ensurePrestart();\n }\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"總體來說reExecutePeriodic方法的邏輯比較簡單,但是,這裏需要注意和delayedExecute方法的不同點:調用reExecutePeriodic方法的時候已經執行過一次任務,所以,並不會觸發線程池的拒絕策略;傳入reExecutePeriodic方法的任務一定是週期性的任務。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"onShutdown方法","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"onShutdown方法是ThreadPoolExecutor類中的鉤子函數,它是在ThreadPoolExecutor類中的shutdown方法中調用的,而在ThreadPoolExecutor類中的onShutdown方法是一個空方法,如下所示。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"void onShutdown() {\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"ThreadPoolExecutor類中的onShutdown方法交由子類實現,所以ScheduledThreadPoolExecutor類覆寫了onShutdown方法,實現了具體的邏輯,ScheduledThreadPoolExecutor類中的onShutdown方法的源碼實現如下所示。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"@Override\nvoid onShutdown() {\n //獲取隊列\n BlockingQueue q = super.getQueue();\n //在線程池已經調用shutdown方法後,是否繼續執行現有延遲任務\n boolean keepDelayed = getExecuteExistingDelayedTasksAfterShutdownPolicy();\n //在線程池已經調用shutdown方法後,是否繼續執行現有定時任務\n boolean keepPeriodic = getContinueExistingPeriodicTasksAfterShutdownPolicy();\n //在線程池已經調用shutdown方法後,不繼續執行現有延遲任務和定時任務\n if (!keepDelayed && !keepPeriodic) {\n //遍歷隊列中的所有任務\n for (Object e : q.toArray())\n //取消任務的執行\n if (e instanceof RunnableScheduledFuture>)\n ((RunnableScheduledFuture>) e).cancel(false);\n //清空隊列\n q.clear();\n }\n //在線程池已經調用shutdown方法後,繼續執行現有延遲任務和定時任務\n else {\n //遍歷隊列中的所有任務\n for (Object e : q.toArray()) {\n //當前任務是RunnableScheduledFuture類型\n if (e instanceof RunnableScheduledFuture) {\n //將任務強轉爲RunnableScheduledFuture類型\n RunnableScheduledFuture> t = (RunnableScheduledFuture>)e;\n //在線程池調用shutdown方法後不繼續的延遲任務或週期任務\n //則從隊列中刪除並取消任務\n if ((t.isPeriodic() ? !keepPeriodic : !keepDelayed) ||\n t.isCancelled()) {\n if (q.remove(t))\n t.cancel(false);\n }\n }\n }\n }\n //最終調用tryTerminate()方法\n tryTerminate();\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"ScheduledThreadPoolExecutor類中的onShutdown方法的主要邏輯就是先判斷線程池調用shutdown方法後,是否繼續執行現有的延遲任務和定時任務,如果不再執行,則取消任務並清空隊列;如果繼續執行,將隊列中的任務強轉爲RunnableScheduledFuture對象之後,從隊列中刪除並取消任務。大家需要好好理解這兩種處理方式。最後調用ThreadPoolExecutor類的tryTerminate方法。有關ThreadPoolExecutor類的tryTerminate方法的源碼解析,大家可以參考【高併發專題】中的《","attrs":{}},{"type":"link","attrs":{"href":"https://xie.infoq.cn/article/bc67b560692368622ede9ea76","title":"","type":null},"content":[{"type":"text","text":"高併發之——通過源碼深度分析線程池中Worker線程的執行流程","attrs":{}}]},{"type":"text","text":"》一文,這裏不再贅述。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"至此,ScheduledThreadPoolExecutor類中的核心方法的源代碼,我們就分析完了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"好了,今天就到這兒吧,我是冰河,我們下期見~~","attrs":{}}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章