最近項目中遇到了一個新的需求,就是實現一個能夠動態添加定時任務的功能。說到這裏,有人可能會說簡單啊,使用quartz就行了,簡單粗暴。然而quartz框架過重了,小項目根本很差操做啊。固然,也有人會說,jdk提供了timer的接口啊,徹底夠用啊。可是咱們項目的需求徹底是多線程的模型啊,而timer是單線程的,so,樓主最後仍是選擇了jdk的線程池。java
Java經過Executors提供四種線程池,分別爲: **newCachedThreadPool :**建立一個可緩存線程池,若是線程池長度超過處理須要,可靈活回收空閒線程,若無可回收,則新建線程。 newFixedThreadPool : 建立一個定長線程池,可控制線程最大併發數,超出的線程會在隊列中等待。 newScheduledThreadPool : 建立一個定長線程池,支持定時及週期性任務執行。 newSingleThreadExecutor : 建立一個單線程化的線程池,它只會用惟一的工做線程來執行任務,保證全部任務按照指定順序(FIFO, LIFO, 優先級)執行。緩存
樓主項目中用到的是newScheduledThreadPool, 就這些吧,再多的樓主就班門弄斧了,Google一下,一大堆。bash
樓主經過單例模式來獲取線程池的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線程池的深刻分析。或者是全局變量啥的,並無找到令樓主滿意的解決方案。ide
既然沒有線程的那就扒一下scheduleAtFixedRate的底層源碼看看是什麼東西吧,果不其然我在源碼中看到了scheduleAtFixedRate方法的具體實現,發現他的返回值是ScheduledFuture。ui
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裏面有什麼東西吧,沒有讓樓主失望,看到了這個this
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)是什麼東西,咱們看到了這個,spa
//經過調用線程的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等,感興趣的小夥伴請移步樓主跟他的小夥伴們的博客