ScheduledThreadPoolExecutor之remove方法
- 2020 年 4 月 7 日
- 筆記
之前用定時任務的線程池,設置了個任務,但是突然今天產品說,某些個操作需要中斷某些任務(如果任務還沒有執行),使其不能再到點執行了。於是查了API果然有這樣一個方法。
一看API,需要移除的是一個Runnable對象,想當然的就把任務調度的傳入的Runable對象保留下來,然後進行刪除。簡要代碼如下
Runnable:
static class Task implements Runnable { @Override public void run() { System.out.println(Instant.now().getEpochSecond()); } }
public static void main(String[] args) { ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(10); Task task = new Task(); scheduledThreadPoolExecutor.schedule(new Task(), 10, TimeUnit.SECONDS); scheduledThreadPoolExecutor.remove(task); System.out.println(Instant.now().getEpochSecond()); }
一執行,完蛋10s過後任務還是執行了,任務並沒有移除
看了下ScheduledThreadPoolExecutor中重寫的remove方法是去他自己的BlockingQueue裏面刪除了一個任務,也就是這個方法ScheduledThreadPoolExecutor.DelayedWorkQueue#remove,這個的入參變成了Object,而且一看這個queue隊列裏面裝的是RunnableScheduledFuture這個對象,這傢伙肯定是實現了Runnable接口的,一看果然是,那麼這個東西放到隊列去的呢?
再看schedule方法是返回了一個值的,猜想了下是不是封裝過我們傳入的Runbale對象,於是決定remove方法的返回值,結果一看返回的ScheduledFuture對象沒有實現Runnable接口,而remove要的Runnable。有一點點坑的地方來了,RunnableScheduledFuture這個是
ScheduledFuture這個的子類,面向接口編程嘛,最後是返回了一個父類接口,但是父類接口沒有實現Runnable,子類才實現了。
最後再看ScheduledThreadPoolExecutor#delayedExecute這個方法裏面剛好把剛才的那個RunnableScheduledFuture對象傳入進去了並且加入到隊列中去了。這樣就和前面聯繫起來了
如此一來 我們只需要把schedule方法的返回值強轉成子類對象RunnableScheduledFuture,保存下來,然後再去調用remove應該可以成功的移除了。
public static void main(String[] args) { ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(10); Task task = new Task(); RunnableScheduledFuture<?> schedule = (RunnableScheduledFuture<?>) scheduledThreadPoolExecutor.schedule(task, 10, TimeUnit.SECONDS); scheduledThreadPoolExecutor.remove(schedule); System.out.println(Instant.now().getEpochSecond()); }
雖然有API供參考,但是就像前面只看API的時候,那個Runnable參數到底該什麼,還得要去看下ScheduledThreadPoolExecutor中別人是怎麼實現的才能知道。