前言
在咱們的平常開發中,不免會使用到線程,部分還會用到多線程併發問題。咱們知道,線程的建立和釋放,須要佔用不小的內存和資源。若是每次須要使用線程時,都new 一個Thread的話,不免會形成資源的浪費,並且能夠無限制建立,之間相互競爭,會致使過多佔用系統資源致使系統癱瘓。不利於擴展,好比如定時執行、按期執行、線程中斷,因此頗有必要了解下ExecutorService的使用。緩存
ExecutorService是Java提供的線程池,也就是說,每次咱們須要使用線程的時候,能夠經過ExecutorService得到線程。它能夠有效控制最大併發線程數,提升系統資源的使用率,同時避免過多資源競爭,避免堵塞,同時提供定時執行、按期執行、單線程、併發數控制等功能,也不用使用TimerTask了。多線程
1.ExecutorService的建立方式
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
全部線程池最終都是經過這個方法來建立的。併發
corePoolSize : 核心線程數,一旦建立將不會再釋放。若是建立的線程數尚未達到指定的核心線程數量,將會繼續建立新的核心線程,直到達到最大核心線程數後,核心線程數將不在增長;若是沒有空閒的核心線程,同時又未達到最大線程數,則將繼續建立非核心線程;若是核心線程數等於最大線程數,則當核心線程都處於激活狀態時,任務將被掛起,等待空閒線程來執行。post
maximumPoolSize : 最大線程數,容許建立的最大線程數量。若是最大線程數等於核心線程數,則沒法建立非核心線程;若是非核心線程處於空閒時,超過設置的空閒時間,則將被回收,釋放佔用的資源。this
keepAliveTime : 也就是當線程空閒時,所容許保存的最大時間,超過這個時間,線程將被釋放銷燬,但只針對於非核心線程。.net
unit : 時間單位,TimeUnit.SECONDS等。線程
workQueue : 任務隊列,存儲暫時沒法執行的任務,等待空閒線程來執行任務。code
threadFactory : 線程工程,用於建立線程。生命週期
handler : 當線程邊界和隊列容量已經達到最大時,用於處理阻塞時的程序隊列
2.線程池的類型
2.1 可緩存線程池
ExecutorService cachePool = Executors.newCachedThreadPool();
看看它的具體建立方式:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
經過它的建立方式能夠知道,建立的都是非核心線程,並且最大線程數爲Interge的最大值,空閒線程存活時間是1分鐘。若是有大量耗時的任務,則不適該建立方式。它只適用於生命週期短的任務。
2.2 單線程池
ExecutorService singlePool = Executors.newSingleThreadExecutor();
顧名思義,也就是建立一個核心線程:
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
只用一個線程來執行任務,保證任務按FIFO順序一個個執行。
2.3 固定線程數線程池
Executors.newFixedThreadPool(3);
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
也就是建立固定數量的可複用的線程數,來執行任務。當線程數達到最大核心線程數,則加入隊列等待有空閒線程時再執行。
2.4 固定線程數,支持定時和週期性任務
ExecutorService scheduledPool = Executors.newScheduledThreadPool(5);
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE,
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue());
}
可用於替代handler.postDelay和Timer定時器等延時和週期性任務。
public ScheduledFuture<?> schedule(Runnable command,
long delay, TimeUnit unit);
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay,
long period,
TimeUnit unit);
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
long initialDelay,
long delay,
TimeUnit unit);
scheduleAtFixedRate和sheduleWithFixedDelay有什麼不一樣呢?
scheduleAtFixedRate:建立並執行一個在給定初始延遲後的按期操做,也就是將在 initialDelay 後開始執行,而後在initialDelay+period 後下一個任務執行,接着在 initialDelay + 2 * period 後執行,依此類推 ,也就是隻在第一次任務執行時有延時。
sheduleWithFixedDelay:建立並執行一個在給定初始延遲後首次啓用的按期操做,隨後,在每一次執行終止和下一次執行開始之間都存在給定的延遲,即總時間是(initialDelay + period)*n
2.4 手動建立線程池
private ExecutorService pool = new ThreadPoolExecutor(3, 10,
10L, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(512), Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
能夠根據本身的需求建立指定的核心線程數和總線程數。
3. 如何終止一個週期性任務呢?
直接上源碼你就懂了:
public final class LgExecutorService {
private ConcurrentHashMap<String, Future> futureMap = new ConcurrentHashMap<>();
private ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(5);
private LgExecutorService() {
}
private static final class InnerExecutorService {
private static final LgExecutorService INSTANCE = new LgExecutorService();
}
public static LgExecutorService getInstance() {
return InnerExecutorService.INSTANCE;
}
public ConcurrentHashMap<String, Future> getFutureMap() {
return futureMap;
}
public void execute(Runnable runnable) {
if (runnable != null) {
executorService.execute(runnable);
}
}
/**
* @param runnable
* @param delay 延遲時間
* @param timeUnit 時間單位
*/
public void sheduler(Runnable runnable, long delay, TimeUnit timeUnit) {
if (runnable != null) {
executorService.schedule(runnable, delay, timeUnit);
}
}
/**
* 執行延時週期性任務
*
* @param runnable {@code LgExecutorSercice.JobRunnable} * @param initialDelay 延遲時間 * @param period 週期時間 * @param timeUnit 時間單位 */ public <T extends JobRunnable> void sheduler(T runnable, long initialDelay, long period, TimeUnit timeUnit) { if (runnable != null) { Future future = executorService.scheduleAtFixedRate(runnable, initialDelay, period, timeUnit); futureMap.put(runnable.getJobId(), future); } } public static abstract class JobRunnable implements Runnable { private String jobId; public JobRunnable(@NonNull String jobId) { this.jobId = jobId; } /** * 強制終止定時線程 */ public void terminal() { try { Future future = LgExecutorService.getInstance().getFutureMap().remove(jobId); future.cancel(true); } finally { System.out.println("jobId " + jobId + " had cancel"); } } public String getJobId() { return jobId; } } }