什么是線程池
官方文檔描述
An {@link ExecutorService} that executes each submitted task using one of possibly
several pooled threads, normally configured using {@link Executors} factory methods.
大體意思是ExecutorService借助池中線程來(lái)處理每一個(gè)提交的任務(wù),通常使用Executors的工廠方法來(lái)配置線程池该溯。
為什么要用線程池
線程池解決了兩個(gè)問題:
- 執(zhí)行大量的異步任務(wù)時(shí),使用線程池減少每個(gè)任務(wù)的調(diào)用開銷啡专,提高性能
執(zhí)行一個(gè)線程任務(wù)的流程:創(chuàng)建線程磕潮、執(zhí)行線程中的任務(wù)石窑、銷毀線程播歼。當(dāng)執(zhí)行大量的異步任務(wù)時(shí)伶跷,頻繁的創(chuàng)建和銷毀線程的時(shí)間占據(jù)大部分比例掰读,使用線程池技術(shù)維護(hù)核心和最大的線程池?cái)?shù)來(lái)避免頻繁的創(chuàng)建和銷毀線程所占據(jù)的時(shí)間秘狞,提高性能。
- 執(zhí)行任務(wù)集合時(shí)蹈集,線程池提供一種限制和管理資源的方案
執(zhí)行任務(wù)集合時(shí)烁试,由于處理器單元是有限的,線程池技術(shù)提供核心線程池拢肆、最大線程池限制線程可同時(shí)運(yùn)行的線程個(gè)數(shù)减响,減少處理器單元的閑置時(shí)間,增加處理器單元的吞吐能力郭怪。
ThreadPoolExecutor支示、AbstractExecutorService、ExecutorService鄙才、Executor之間的關(guān)系
通過(guò)下面代碼可以很清楚了解到他們之間的關(guān)系颂鸿,圖我就不花了。攒庵。嘴纺。
public class ThreadPoolExecutor extends AbstractExecutorService
public abstract class AbstractExecutorService implements ExecutorService
public interface ExecutorService extends Executor {
void shutdown(); // 關(guān)閉所有任務(wù)
List<Runnable> shutdownNow(); // 立即關(guān)閉所有任務(wù)
boolean isShutdown(); // 是否被關(guān)閉
boolean isTerminated(); // 是否被終止運(yùn)行
Future<?> submit(Runnable task); // 提交任務(wù)到線程池中運(yùn)行,最后還是交于execute方法執(zhí)行
....
}
public interface Executor {
void execute(Runnable command); // 執(zhí)行任務(wù)
}
ThreadPoolExecutor類構(gòu)造函數(shù)參數(shù)分析
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
....
}
- corePoolSize:保持在線程池中的線程線程數(shù)浓冒,除非調(diào)用allowCoreThreadTimeOut方法栽渴,否則該線程閑置也不會(huì)被銷毀
- maximumPoolSize:線程池中允許創(chuàng)建的最大線程數(shù)(包含核心線程池)
- keepAliveTime:當(dāng)線程池中線程創(chuàng)建數(shù)大于核心線程數(shù),沒有新任務(wù)可以被處理而閑置keepAliveTime時(shí)間時(shí)自動(dòng)銷毀該類型線程
- unit:keepAliveTime的時(shí)間單位
- workQueue:工作隊(duì)列稳懒,這個(gè)隊(duì)列將維持被執(zhí)行的任務(wù)
- threadFactory:線程工程闲擦,用于創(chuàng)建新的線程
- handler:當(dāng)線程任務(wù)被拒時(shí)的處理者
線程池使用demo
下面例子是線程池的簡(jiǎn)單用法,不具備代表性场梆。但是墅冷,確是比較有意思的一個(gè)例子,Callable和Future搭配可以實(shí)現(xiàn)等待多個(gè)任務(wù)完成后統(tǒng)一處理辙谜。有一些很雞肋的場(chǎng)景俺榆,例如通過(guò)多個(gè)接口獲取主頁(yè)不同類型數(shù)據(jù)后刷新界面,哎装哆,主要是服務(wù)端寫成了多個(gè)接口罐脊,我也是很無(wú)奈╮(╯▽╰)╭定嗓。
import java.util.concurrent.*;
public class Main {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(1000);
return "callable sleep 1s";
}
};
Callable<String> callable1 = new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(2000);
return "callable sleep 2s";
}
};
ExecutorService executorService = Executors.newFixedThreadPool(2);
executorService.submit(new Runnable() {
@Override
public void run() {
System.out.println("I'm runnable. I'm finished.");
}
});
Future<String> submit = executorService.submit(callable);
Future<String> submit1 = executorService.submit(callable1);
String s = submit.get();
String s1 = submit1.get();
System.out.println("callable resule: s=>" + s + " s1=>" + s1);
}
}
輸出:
I'm runnable. I'm finished.
callable resule: s=>callable sleep 1s s1=>callable sleep 2s
線程池鉤子方法
/**
* <dt>Hook methods</dt>
*
* <dd>This class provides {@code protected} overridable
* {@link #beforeExecute(Thread, Runnable)} and
* {@link #afterExecute(Runnable, Throwable)} methods that are called
* before and after execution of each task. These can be used to
* manipulate the execution environment; for example, reinitializing
* ThreadLocals, gathering statistics, or adding log entries.
*/
主要的意思是系統(tǒng)提供兩個(gè)鉤子方法beforeExecute和afterExecute方法,他們分別是在任務(wù)執(zhí)行之前和執(zhí)行之后調(diào)用萍桌。用途宵溅,比如重新初始化線程變量、收集靜態(tài)數(shù)據(jù)上炎、添加日志實(shí)體等恃逻。下面是官方的例子:
class PausableThreadPoolExecutor extends ThreadPoolExecutor {
private boolean isPaused;
private ReentrantLock pauseLock = new ReentrantLock();
private Condition unpaused = pauseLock.newCondition();
public PausableThreadPoolExecutor(...) { super(...); }
protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
pauseLock.lock();
try {
while (isPaused) unpaused.await();
} catch (InterruptedException ie) {
t.interrupt();
} finally {
pauseLock.unlock();
}
}
public void pause() {
pauseLock.lock();
try {
isPaused = true;
} finally {
pauseLock.unlock();
}
}
public void resume() {
pauseLock.lock();
try {
isPaused = false;
unpaused.signalAll();
} finally {
pauseLock.unlock();
}
}
}
本文對(duì)于線程池的講解比較淺顯,只要是講解線程池的基礎(chǔ)使用