源於開發
最近專案中遇到了一個新的需求,就是實現一個可以動態新增定時任務的功能。說到這裡,有人可能會說簡單啊,使用quartz就好了,簡單粗暴。然而quartz框架太重了,小專案根本不好操作啊。當然,也有人會說,jdk提供了timer的介面啊,完全夠用啊。但是我們專案的需求完全是多執行緒的模型啊,而timer是單執行緒的,so,樓主最後還是選擇了jdk的執行緒池。
執行緒池是什麼
Java通過Executors提供四種執行緒池,分別為:
**newCachedThreadPool :**建立一個可快取執行緒池,如果執行緒池長度超過處理需要,可靈活回收空閒執行緒,若無可回收,則新建執行緒。
newFixedThreadPool : 建立一個定長執行緒池,可控制執行緒最大併發數,超出的執行緒會在佇列中等待。
newScheduledThreadPool : 建立一個定長執行緒池,支援定時及週期性任務執行。
newSingleThreadExecutor : 建立一個單執行緒化的執行緒池,它只會用唯一的工作執行緒來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先順序)執行。
樓主專案中用到的是newScheduledThreadPool, 就這些吧,再多的樓主就班門弄斧了,Google一下,一大堆。
執行緒池service的獲取
樓主通過單例模式來獲取執行緒池的service,程式碼如下:
/**
* 執行緒池建立.
* @author wuhf
* @date 2018/01/16
*/
public class ThreadPoolUtils {
private static ScheduledExecutorService executorService;
private ThreadPoolUtils() {
//手動建立執行緒池.
executorService = new ScheduledThreadPoolExecutor(10,
new BasicThreadFactory.Builder().namingPattern("syncdata-schedule-pool-%d").daemon(true).build());
}
private static class PluginConfigHolder {
private final static ThreadPoolUtils INSTANCE = new ThreadPoolUtils();
}
public static ThreadPoolUtils getInstance() {
return PluginConfigHolder.INSTANCE;
}
public ScheduledExecutorService getThreadPool(){
return executorService;
}
}
複製程式碼
中斷某一個正在執行的執行緒程式碼實現
廢話就不多說了,程式碼如下:
/**
* 中斷執行緒池的某個任務.
*/
public class InterruptThread implements Runnable {
private int num;
public InterruptThread (int num){
this.num = num;
}
public static void main(String[] args) throws InterruptedException {
Thread interruptThread = new Thread(new InterruptThread(1));
ScheduledFuture<?> t = ThreadPoolUtils.getInstance().getThreadPool().scheduleAtFixedRate(interruptThread,0,2,
TimeUnit.SECONDS);
InterruptThread interruptThread1 = new InterruptThread(2);
ThreadPoolUtils.getInstance().getThreadPool().scheduleAtFixedRate(interruptThread1,0,2,
TimeUnit.SECONDS);
InterruptThread interruptThread2 = new InterruptThread(3);
ThreadPoolUtils.getInstance().getThreadPool().scheduleAtFixedRate(interruptThread2,0,2,
TimeUnit.SECONDS);
Thread.sleep(5000);
//終止正在執行的執行緒interruptThread
t.cancel(true);
while (true){
}
}
@Override
public void run() {
System.out.println("this is a thread" + num);
}
}
複製程式碼
踩坑記錄
樓主在使用如下程式碼時,突然想到當這個定時任務需要被停止時該如何停止執行緒執行
ThreadPoolUtils.getInstance().getThreadPool().scheduleAtFixedRate(interruptThread,0,2,
TimeUnit.SECONDS);
複製程式碼
既然我有這樣的需求,那就Google一下吧,找了大半圈,愣是沒找到相關資料,都是一些關於Java執行緒池的深入分析。或者是全域性變數啥的,並沒有找到令樓主滿意的解決方案。
既然沒有執行緒的那就扒一下scheduleAtFixedRate的底層原始碼看看是什麼東西吧,果不其然我在原始碼中看到了scheduleAtFixedRate方法的具體實現,發現他的返回值是ScheduledFuture。
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay,
long period,
TimeUnit unit) {
if (command == null || unit == null)
throw new NullPointerException();
if (period <= 0)
throw new IllegalArgumentException();
ScheduledFutureTask<Void> sft =
new ScheduledFutureTask<Void>(command,
null,
triggerTime(initialDelay, unit),
unit.toNanos(period));
RunnableScheduledFuture<Void> t = decorateTask(command, sft);
sft.outerTask = t;
delayedExecute(t);
return t;
}
複製程式碼
接著往下我們再看看ScheduledFuture裡面有什麼東西吧,沒有讓樓主失望,看到了這個
public boolean cancel(boolean mayInterruptIfRunning) {
boolean cancelled = super.cancel(mayInterruptIfRunning);
if (cancelled && removeOnCancel && heapIndex >= 0)
remove(this);
return cancelled;
}
//從執行緒的執行佇列中移除當前執行緒
public boolean remove(Runnable task) {
boolean removed = workQueue.remove(task);
tryTerminate(); // In case SHUTDOWN and now empty
return removed;
}
複製程式碼
再往上查super.cancel(mayInterruptIfRunning)是什麼東西,我們看到了這個,
//通過呼叫執行緒的interrupt方法終止執行緒執行
public boolean cancel(boolean mayInterruptIfRunning) {
if (!(state == NEW &&
UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
return false;
try { // in case call to interrupt throws exception
if (mayInterruptIfRunning) {
try {
Thread t = runner;
if (t != null)
t.interrupt();
} finally { // final state
UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
}
}
} finally {
finishCompletion();
}
return true;
}
複製程式碼
到這裡所有的問題都迎刃而解。
總結一下吧
專案中總是會遇到比較難搞的解決方案,當Google不太好找時,翻一下jdk的原始碼或許也是一個不錯的方法。最後宣傳一下樓主的部落格,部落格已經遷移到騰訊雲上,跟幾個大學的小夥伴一起經營,內容涵蓋java,Android等,感興趣的小夥伴請移步樓主跟他的小夥伴們的部落格