java併發程式設計之執行緒,執行緒池,ansync執行緒池原始碼解析
前言
java開源長了, 程式碼久了,網上對於執行緒那是眾說紛紜,一直縈繞我心頭的,jdk執行緒池好還是spring執行緒池好?
結果發現,spring生命週期管理的執行緒池,其底層就是私有ThreadPoolExecutor類,spring(具體管理ThreadPoolTaskExecutor類)只是對其一種封裝呼叫而已;
而我們日常使用jdk執行緒池 - Executor框架, ThreadPoolExecutor是Executor框架的核心實現類;
說到底,jdk執行緒池與spring執行緒池都是在使用ThreadPollExecutor基礎上開發;
JDK執行緒
古老的extend,implment Runnable的實現執行緒的方式就不說了,也就是測試類寫寫
科普下, jdk8 lambda格式方便快捷的使用
new Thread(() -> System.out.println("執行緒列印...")).start();
ThreadPollExecutor
炒的火熱jdk執行緒池的的核心實現類。
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); }
- corePoolSize: 核心執行緒數。預設情況下執行緒池是空的,只有有任務提交的時候才會去建立執行緒。當執行的執行緒少於corePoolSize的時候,新建任務將建立核心執行緒,如果的等於或者大於corePoolSize的時候將不會建立核心執行緒,建立普通執行緒。可以呼叫prestartAllcoreThread的方法來提前建立並啟動所有的核心執行緒。
- maximumPoolSize:執行緒池所允許的最大的執行緒數量。當任務佇列滿了的話執行緒數小於maximumPoolSize的值的話,新建任務還是會建立新的執行緒的。
- keepAliveTime : 非核心執行緒閒置的超時時間,第一是非核心的執行緒第二是閒置狀態。呼叫allowCoreThreadTimeOut的時候該設定也會作用再核心的執行緒上面。
- TimeUnit : 超時的時間單位。DAYS(天),HOURS(小時),MINUTES(f分鐘),SECONDS(秒),MILLISECONDS(毫秒).
- workQueue : 任務佇列(阻塞佇列)。當前執行緒書大於corePoolSize的大小的時候,會將任務加入阻塞佇列裡面。該佇列是BlockingQueue型別的。
- ThreadFactory : 執行緒工場。我們可以自己去定義。
- RejectedExecutionHandler : 飽和策略。這是當任務佇列和執行緒數都滿了的時候所採取的的對應策略預設是AbordPolicy表示無法處理新的任務,並丟擲RejectedExecutionException異常。
- CallerRunsPolicy : 用呼叫者所在的執行緒來處理任務。
- DisCardPolicy : 不能執行任務並將任務刪除。
- DisCardOldesPolicy : 丟棄佇列最近的任務,並執行當前的任務, 會一直執行下去。
Executore類(框架)
通過idea原始碼方法看到, Executors類下, 有不少快捷建立執行緒池方法 (idea檢視類方法alt+7), 下面介紹常用的5種建立方法;
FixedThreadPool
FixedThreadPool是可重的固定執行緒數的執行緒池。
//建立FixedThreadPool
Executors.newFixedThreadPool(5);
//建立所需要的引數
public static ExecutorService newFixedThreadPool(int nThreads) {
//最後呼叫的都是ThreadPoolExecutor
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
我們只需要傳如需要建立的執行緒的數量,也就是執行緒池的大小。我們可以看到構造方法,傳入的執行緒的數量就是核心執行緒的數量。也就是FixedThreadPool會建立固定數量核心執行緒的執行緒池,並且這些核心執行緒不會被回收,任務超過執行緒的數量將存入佇列中。
CachedThreadPool
該執行緒池是根據需要去建立執行緒的。
//建立快取執行緒池
Executors.newCachedThreadPool();
//構造方法
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
我們可以看出,這裡面的核心執行緒數是0,而執行緒的最大值是Integer.Max_VALUE。閒置超時間是一分鐘。預設佇列可以保證任務順序的執行。CacheThreadPool適合大量的需要立即處理並且耗時較少的任務。
SingleThreadExecutor
該類是使用單個執行緒的執行緒池。
//建立方法
Executors.newSingleThreadExecutor();
//構造方法
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
corePoolSize和maximumPoolSize都是1,意味著SingleThreadExecutor只有一個核心執行緒。其他的引數和FixedThreadPool一樣。如果已經建立了一個執行緒再來一個任務的時候會將該任務加入到任務佇列裡面,確保了所有任務的執行順序。
ScheduledThreadPool
ScheduledThreadPool是一個能實現定是和週期性任務的執行緒池。
//建立
Executors.newScheduledThreadPool(5);
//構造方法
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE,
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue());
}
//最後還是呼叫的
ThreadPoolExecutor的構造方法。
當執行任務的時候,會先將任務包裝成ScheduledFutrueTask並新增到DelayedWorkQueue裡面,當沒超過corePoolSize的時候,會建立執行緒,人後去DelayedWorkQueue佇列裡面去拿任務,並不是立即的執行。當執行完任務的時候會將ScheduledFutrueTask中的time變數改為下次要執行的時間並放回DelayedWorkQueue中。
Spring執行緒池
@Ansync
傳統方式
springContext.xml配置管理, 其執行緒池生命週期由spring來管理
<bean id="threadPoolTaskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<!-- 核心執行緒數,預設為1 -->
<property name="corePoolSize" value="10" />
<!-- 最大執行緒數,預設為Integer.MAX_VALUE -->
<property name="maxPoolSize" value="50" />
<!-- 佇列最大長度,一般需要設定值>=notifyScheduledMainExecutor.maxNum;預設為Integer.MAX_VALUE
<property name="queueCapacity" value="1000" /> -->
<!-- 執行緒池維護執行緒所允許的空閒時間,預設為60s -->
<property name="keepAliveSeconds" value="300" />
<!-- 執行緒池對拒絕任務(無執行緒可用)的處理策略,目前只支援AbortPolicy、CallerRunsPolicy;預設為後者 -->
<property name="rejectedExecutionHandler">
<!-- AbortPolicy:直接丟擲java.util.concurrent.RejectedExecutionException異常 -->
<!-- CallerRunsPolicy:主執行緒直接執行該任務,執行完之後嘗試新增下一個任務到執行緒池中,可以有效降低向執行緒池內新增任務的速度 -->
<!-- DiscardOldestPolicy:拋棄舊的任務、暫不支援;會導致被丟棄的任務無法再次被執行 -->
<!-- DiscardPolicy:拋棄當前任務、暫不支援;會導致被丟棄的任務無法再次被執行 -->
<bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" />
</property>
</bean>
註解方式
註解又分為 預設非執行緒池方式,執行緒池方式,這裡已執行緒池方式為例子
<?xml version="1.0" encoding="UTF-8"?>
<!--Spring框架的xml標籤定義文件, 可訪問http://www.springframework.org/schema/task/檢視最新task元件的xml標籤文件-->
<beans xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.2.xsd">
<!--掃描專案例項化@Component,@Service,@Controller修飾的類-->
<context:component-scan base-package="com.your_app" />
<!-- 在程式碼中@Async不加引數就會使用task:annotation-driven標籤定義的executor-->
<task:annotation-driven executor="myExecutor"/>
<!-- 在程式碼中@Async("myExecutor")可以顯式指定executor為"myExecutor"-->
<task:executor id="myExecutor"
pool-size="5-25"
queue-capacity="100"
rejection-policy="CALLER_RUNS"/>
</beans>
@Async
void doSomething(String s) { //可以帶引數!
// this will be executed asynchronously
}
具體配置歡迎觀看
https://blog.csdn.net/caib1109/article/details/51623089
呼叫發現,其org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor 類, 原始碼檢視,
初始化,也是使用ThreadPoolExecutor實現操作,具體指示設定對應的引數值而已;
好了 檢視到此結束
文章涉及來源:
SpringMVC非同步處理之@Async(附原始碼 - 單元測試通過)
https://blog.csdn.net/caib1109/article/details/51623089
https://www.cnblogs.com/olmlo/p/4806967.html
Java多執行緒-五中執行緒池分析以及AnsyncTask原始碼分析
https://blog.csdn.net/jsonchumpklutz/article/details/78398534