本篇來看下java線程池相關技術的實現和使用方式。java
一開始咱們想要實現多線程最一般的作法是:編程
new Thread(new Runnable() { public void run() { System.out.println("raw thread"); } }).start();
這種方式,這種實現方式也沒有什麼很差,只是若是線程一多的話很差對全部的線程進行統一管理。而後java有了線程池技術,咱們能夠經過線程池技術來替換實現上面的方式。多線程
ExecutorService executorPool = Executors.newCachedThreadPool(); Future<String> future = executorPool.submit(new Callable<String>() { public String call() throws Exception { return "future finish"; } }); try { System.out.println(future.get()); } catch (Exception e) { e.printStackTrace(); }
Executors有以下幾種方式建立線程:ide
newCachedThreadPool函數
newFixedThreadPool線程
newScheduledThreadPoolcode
上面三種方式最終都是調用ThreadPoolExecutor的構造函數進行線程池的建立,只是傳入的參數不同,而實現不一樣的線程池對象。對象
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
corePoolSize:建立線程池時建立多少個線程。隊列
maximumPoolSize:這個線程池中對多能有多少個線程。get
keepAliveTime:當線程數量超過corePoolSize時,多餘的空閒線程最大的存活時間。也就是說多餘的線程在keepAliveTime時間仍是沒有處理任何的任務將會被終止。
unit:時間單位
workQueue:這個線程池中線程處理任務的的任務隊列。
threadFactory:建立新線程的線程工廠。
handler:當線程數量達到maximumPoolSize,對新加入的任務的處理策略。通常不多使用這個參數基本都採用默認的handler。
上面的例子中咱們向線程池中提交了一個Callable,並接受一個返回值Future。Callable可能會是一個很是耗時的操做可是使用方有不想阻塞等待其返回再繼續執行,這時Callable執行完後會將結果放到Future中,使用方能夠在須要的時候去判斷是否Callable已經執行完成,若是完成就能夠經過Future拿到其返回值。
任務定時調度線程的使用:
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); scheduledExecutorService.scheduleAtFixedRate(new Runnable() { public void run() { System.out.println("schedule task with fixed rate:" + System.currentTimeMillis()); } }, 2000, 1000, TimeUnit.MILLISECONDS); scheduledExecutorService.scheduleWithFixedDelay(new Runnable() { public void run() { System.out.println("schedule task with fixed delay:" + System.currentTimeMillis()); int count = Integer.MAX_VALUE; while (count-- > 0){ } System.out.println("time:" + System.currentTimeMillis()); } }, 2000, 1000, TimeUnit.MILLISECONDS);
ScheduledExecutorService有兩種定時調度的方式:
scheduleAtFixedRate:以固定速率進行調度,意思是任何兩個被調度的任務之間的時間間隔是固定的。第二個任務的調度時間(開始執行時間)= 第一個任務的調度時間 + 間隔時間
scheduleWithFixedDelay:第二個任務的調度時間 = 第一個任務的調度時間 + 第一個任務的執行時間 + 間隔時間
上面介紹了ScheduledExecutorService來作定時任務,在編程的過程當中還可使用Timer來作定時任務,代碼以下:
timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { try { doSomething(); } catch (Exception e) { System.out.println("timer excute exception", e); } } }, 1000 * 3, 1000);
其第一參數是一個TimerTask,第二第三個參數scheduledExecutorService.scheduleAtFixedRate
這個調用的第二三個參數一致。
我以爲最好的參考仍是閱讀相關源碼去理解Executor的使用方式,這樣本身才能理解的比較深刻同時作到活學活用。線程池的的核心實現ThreadPoolExecutor,想了解更多仍是本身去look look源碼吧。