深度源碼解析Java 線(xiàn)程池的實(shí)現(xiàn)原理
java 系統(tǒng)的運(yùn)行歸根到底是程序的運(yùn)行,程序的運(yùn)行歸根到底是代碼的執(zhí)行,代碼的執(zhí)行歸根到底是虛擬機(jī)的執(zhí)行,虛擬機(jī)的執(zhí)行其實(shí)就是操作系統(tǒng)的線(xiàn)程在執(zhí)行,并且會(huì)占用一定的系統(tǒng)資源,如CPU、內(nèi)存、磁盤(pán)、網(wǎng)絡(luò)等等。所以,如何高效的使用這些資源就是程序員在平時(shí)寫(xiě)代碼時(shí)候的一個(gè)努力的方向。本文要說(shuō)的線(xiàn)程池就是一種對(duì) CPU 利用的優(yōu)化手段。
線(xiàn)程池,百度百科是這么解釋的:
線(xiàn)程池是一種多線(xiàn)程處理形式,處理過(guò)程中將任務(wù)添加到隊(duì)列,然后在創(chuàng)建線(xiàn)程后自動(dòng)啟動(dòng)這些任務(wù)。線(xiàn)程池線(xiàn)程都是后臺(tái)線(xiàn)程。每個(gè)線(xiàn)程都使用默認(rèn)的堆棧大小,以默認(rèn)的優(yōu)先級(jí)運(yùn)行,并處于多線(xiàn)程單元中。如果某個(gè)線(xiàn)程在托管代碼中空閑(如正在等待某個(gè)事件),則線(xiàn)程池將插入另一個(gè)輔助線(xiàn)程來(lái)使所有處理器保持繁忙。如果所有線(xiàn)程池線(xiàn)程都始終保持繁忙,但隊(duì)列中包含掛起的工作,則線(xiàn)程池將在一段時(shí)間后創(chuàng)建另一個(gè)輔助線(xiàn)程但線(xiàn)程的數(shù)目永遠(yuǎn)不會(huì)超過(guò)最大值。超過(guò)最大值的線(xiàn)程可以排隊(duì),但他們要等到其他線(xiàn)程完成后才啟動(dòng)。
線(xiàn)程池,其實(shí)就是維護(hù)了很多線(xiàn)程的池子,類(lèi)似這樣的技術(shù)還有很多的,例如:HttpClient 連接池、數(shù)據(jù)庫(kù)連接池、內(nèi)存池等等。
線(xiàn)程池的優(yōu)點(diǎn)
在 Java 并發(fā)編程框架中的線(xiàn)程池是運(yùn)用場(chǎng)景最多的技術(shù),幾乎所有需要異步或并發(fā)執(zhí)行任務(wù)的程序都可以使用線(xiàn)程池。在開(kāi)發(fā)過(guò)程中,合理地使用線(xiàn)程池能夠帶來(lái)至少以下4個(gè)好處。
第一:降低資源消耗。通過(guò)重復(fù)利用已創(chuàng)建的線(xiàn)程降低線(xiàn)程創(chuàng)建和銷(xiāo)毀造成的消耗;
第二:提高響應(yīng)速度。當(dāng)任務(wù)到達(dá)時(shí),任務(wù)可以不需要等到線(xiàn)程創(chuàng)建就能立即執(zhí)行;
第三:提高線(xiàn)程的可管理性。線(xiàn)程是稀缺資源,如果無(wú)限制地創(chuàng)建,不僅會(huì)消耗系統(tǒng)資源,還會(huì)降低系統(tǒng)的穩(wěn)定性,使用線(xiàn)程池可以進(jìn)行統(tǒng)一分配、調(diào)優(yōu)和監(jiān)控。
第四:提供更強(qiáng)大的功能,比如延時(shí)定時(shí)線(xiàn)程池;
線(xiàn)程池的實(shí)現(xiàn)原理
當(dāng)向線(xiàn)程池提交一個(gè)任務(wù)之后,線(xiàn)程池是如何處理這個(gè)任務(wù)的呢?下面就先來(lái)看一下它的主要處理流程。先來(lái)看下面的這張圖,然后我們一步一步的來(lái)解釋。

當(dāng)使用者將一個(gè)任務(wù)提交到線(xiàn)程池以后,線(xiàn)程池是這么執(zhí)行的:
①首先判斷核心的線(xiàn)程數(shù)是否已滿(mǎn),如果沒(méi)有滿(mǎn),那么就去創(chuàng)建一個(gè)線(xiàn)程去執(zhí)行該任務(wù);否則請(qǐng)看下一步
②如果線(xiàn)程池的核心線(xiàn)程數(shù)已滿(mǎn),那么就繼續(xù)判斷任務(wù)隊(duì)列是否已滿(mǎn),如果沒(méi)滿(mǎn),那么就將任務(wù)放到任務(wù)隊(duì)列中;否則請(qǐng)看下一步
③如果任務(wù)隊(duì)列已滿(mǎn),那么就判斷線(xiàn)程池是否已滿(mǎn),如果沒(méi)滿(mǎn),那么就創(chuàng)建線(xiàn)程去執(zhí)行該任務(wù);否則請(qǐng)看下一步;
④如果線(xiàn)程池已滿(mǎn),那么就根據(jù)拒絕策略來(lái)做出相應(yīng)的處理;
上面的四步其實(shí)就已經(jīng)將線(xiàn)程池的執(zhí)行原理描述結(jié)束了。如果不明白沒(méi)有關(guān)系,先一步一步往下看,上面涉及到的線(xiàn)程池的專(zhuān)有名詞都會(huì)詳細(xì)的介紹到。
我們?cè)谄綍r(shí)的開(kāi)發(fā)中,線(xiàn)程池的使用基本都是基于ThreadPoolExexutor類(lèi),他的繼承體系是這樣子的:

那既然說(shuō)在使用中都是基于ThreadPoolExecutor的那么我們就重點(diǎn)分析這個(gè)類(lèi)。
至于他構(gòu)造體系中的其他的類(lèi)或者是接口中的屬性,這里就不去截圖了,完全沒(méi)有必要。小伙伴如果實(shí)在想看就自己去打開(kāi)代碼看一下就行了。
ThreadPoolExecutor
在《阿里巴巴 java 開(kāi)發(fā)手冊(cè)》中指出了線(xiàn)程資源必須通過(guò)線(xiàn)程池提供,不允許在應(yīng)用中自行顯示的創(chuàng)建線(xiàn)程,這樣一方面是線(xiàn)程的創(chuàng)建更加規(guī)范,可以合理控制開(kāi)辟線(xiàn)程的數(shù)量;另一方面線(xiàn)程的細(xì)節(jié)管理交給線(xiàn)程池處理,優(yōu)化了資源的開(kāi)銷(xiāo)。
其原文描述如下:

在ThreadPoolExecutor類(lèi)中提供了四個(gè)構(gòu)造方法,但是他的四個(gè)構(gòu)造器中,實(shí)際上最終都會(huì)調(diào)用同一個(gè)構(gòu)造器,只不過(guò)是在另外三個(gè)構(gòu)造器中,如果有些參數(shù)不傳ThreadPoolExecutor會(huì)幫你使用默認(rèn)的參數(shù)。所以,我們直接來(lái)看這個(gè)完整參數(shù)的構(gòu)造器,來(lái)徹底剖析里面的參數(shù)。
public class ThreadPoolExecutor extends AbstractExecutorService {
......
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0){
throw new IllegalArgumentException();
}
if (workQueue == null || threadFactory == null || handler == null){
throw new NullPointerException();
}
this.acc = System.getSecurityManager() == null ? null : AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
}
主要參數(shù)就是下面這幾個(gè):
- corePoolSize:線(xiàn)程池中的核心線(xiàn)程數(shù),包括空閑線(xiàn)程,也就是核心線(xiàn)程數(shù)的大?。?/li>
- maximumPoolSize:線(xiàn)程池中允許的最多的線(xiàn)程數(shù),也就是說(shuō)線(xiàn)程池中的線(xiàn)程數(shù)是不可能超過(guò)該值的;
- keepAliveTime:當(dāng)線(xiàn)程池中的線(xiàn)程數(shù)大于 corePoolSize 的時(shí)候,在超過(guò)指定的時(shí)間之后就會(huì)將多出 corePoolSize 的的空閑的線(xiàn)程從線(xiàn)程池中刪除;
- unit:keepAliveTime 參數(shù)的單位(常用的秒為單位);
- workQueue:用于保存任務(wù)的隊(duì)列,此隊(duì)列僅保持由 executor 方法提交的任務(wù) Runnable 任務(wù);
- threadFactory:線(xiàn)程池工廠,他主要是為了給線(xiàn)程起一個(gè)標(biāo)識(shí)。也就是為線(xiàn)程起一個(gè)具有意義的名稱(chēng);
- handler:拒絕策略
阻塞隊(duì)列
workQueue 有多種選擇,在 JDK 中一共提供了 7 中阻塞對(duì)列,分別為:
- ArrayBlockingQueue : 一個(gè)由數(shù)組結(jié)構(gòu)組成的有界阻塞隊(duì)列。 此隊(duì)列按照先進(jìn)先出(FIFO)的原則對(duì)元素進(jìn)行排序。默認(rèn)情況下不保證訪(fǎng)問(wèn)者公平地訪(fǎng)問(wèn)隊(duì)列 ,所謂公平訪(fǎng)問(wèn)隊(duì)列是指阻塞的線(xiàn)程,可按照阻塞的先后順序訪(fǎng)問(wèn)隊(duì)列。非公平性是對(duì)先等待的線(xiàn)程是不公平的,當(dāng)隊(duì)列可用時(shí),阻塞的線(xiàn)程都可以競(jìng)爭(zhēng)訪(fǎng)問(wèn)隊(duì)列的資格。
- LinkedBlockingQueue : 一個(gè)由鏈表結(jié)構(gòu)組成的有界阻塞隊(duì)列。 此隊(duì)列的默認(rèn)和最大長(zhǎng)度為Integer.MAX_VALUE。 此隊(duì)列按照先進(jìn)先出的原則對(duì)元素進(jìn)行排序。
- PriorityBlockingQueue : 一個(gè)支持優(yōu)先級(jí)排序的無(wú)界阻塞隊(duì)列。 (雖然此隊(duì)列邏輯上是無(wú)界的,但是資源被耗盡時(shí)試圖執(zhí)行 add 操作也將失敗,導(dǎo)致 OutOfMemoryError)
- DelayQueue: 一個(gè)使用優(yōu)先級(jí)隊(duì)列實(shí)現(xiàn)的無(wú)界阻塞隊(duì)列。 元素的一個(gè)無(wú)界阻塞隊(duì)列,只有在延遲期滿(mǎn)時(shí)才能從中提取元素
- SynchronousQueue: 一個(gè)不存儲(chǔ)元素的阻塞隊(duì)列。 一種阻塞隊(duì)列,其中每個(gè)插入操作必須等待另一個(gè)線(xiàn)程的對(duì)應(yīng)移除操作 ,反之亦然。(SynchronousQueue 該隊(duì)列不保存元素)
- LinkedTransferQueue: 一個(gè)由鏈表結(jié)構(gòu)組成的無(wú)界阻塞隊(duì)列。 相對(duì)于其他阻塞隊(duì)列LinkedTransferQueue多了tryTransfer和transfer方法。
- LinkedBlockingDeque: 一個(gè)由鏈表結(jié)構(gòu)組成的雙向阻塞隊(duì)列。 是一個(gè)由鏈表結(jié)構(gòu)組成的雙向阻塞隊(duì)列
在以上的7個(gè)隊(duì)列中,線(xiàn)程池中常用的是ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue,
隊(duì)列中的常用的方法如下:
| 類(lèi)型 | 方法 | 含義 | 特點(diǎn) |
|---|---|---|---|
| 拋異常 | add | 添加一個(gè)元素 | 如果隊(duì)列滿(mǎn),拋出異常 IllegalStateException |
| 拋異常 | remove | 返回并刪除隊(duì)列的頭節(jié)點(diǎn) | 如果隊(duì)列空,拋出異常 NoSuchElementException |
| 拋異常 | element | 返回隊(duì)列頭節(jié)點(diǎn) | 如果隊(duì)列空,拋出異常 NoSuchElementException |
| 不拋異常,但是不阻塞 | offer | 添加一個(gè)元素 | 添加成功,返回 true,添加失敗,返回 false |
| 不拋異常,但是不阻塞 | poll | 返回并刪除隊(duì)列的頭節(jié)點(diǎn) | 如果隊(duì)列空,返回 null |
| 不拋異常,但是不阻塞 | peek | 返回隊(duì)列頭節(jié)點(diǎn) | 如果隊(duì)列空,返回 null |
| 阻塞 | put | 添加一個(gè)元素 | 如果隊(duì)列滿(mǎn),阻塞 |
| 阻塞 | take | 返回并刪除隊(duì)列的頭節(jié)點(diǎn) | 如果隊(duì)列空,阻塞 |
關(guān)于阻塞隊(duì)列,介紹到這里也就基本差不多了。
線(xiàn)程池工廠
線(xiàn)程池工廠,就像上面已經(jīng)介紹的,目的是為了給線(xiàn)程起一個(gè)有意義的名字。用起來(lái)也非常的簡(jiǎn)單,只需要實(shí)現(xiàn)ThreadFactory接口即可
public class CustomThreadFactory implements ThreadFactory {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName("我是你們自己定義的線(xiàn)程名稱(chēng)");
return thread;
}
}
具體的使用就不去廢話(huà)了。
拒絕策略
線(xiàn)程池有四種默認(rèn)的拒絕策略,分別為:
- AbortPolicy:這是線(xiàn)程池默認(rèn)的拒絕策略,在任務(wù)不能再提交的時(shí)候,拋出異常,及時(shí)反饋程序運(yùn)行狀態(tài)。如果是比較關(guān)鍵的業(yè)務(wù),推薦使用此拒絕策略,這樣子在系統(tǒng)不能承載更大的并發(fā)量的時(shí)候,能夠及時(shí)的通過(guò)異常發(fā)現(xiàn);
- DiscardPolicy:丟棄任務(wù),但是不拋出異常。如果線(xiàn)程隊(duì)列已滿(mǎn),則后續(xù)提交的任務(wù)都會(huì)被丟棄,且是靜默丟棄。這玩意不建議使用;
- DiscardOldestPolicy:丟棄隊(duì)列最前面的任務(wù),然后重新提交被拒絕的任務(wù)。這玩意不建議使用;
- CallerRunsPolicy:如果任務(wù)添加失敗,那么主線(xiàn)程就會(huì)自己調(diào)用執(zhí)行器中的 executor 方法來(lái)執(zhí)行該任務(wù)。這玩意不建議使用;
也就是說(shuō)關(guān)于線(xiàn)程池的拒絕策略,最好使用默認(rèn)的。這樣能夠及時(shí)發(fā)現(xiàn)異常。如果上面的都不能滿(mǎn)足你的需求,你也可以自定義拒絕策略,只需要實(shí)現(xiàn) RejectedExecutionHandler 接口即可
public class CustomRejection implements RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.out.println("你自己想怎么處理就怎么處理");
}
}
看到這里,我們?cè)賮?lái)畫(huà)一張圖來(lái)總結(jié)和概括下線(xiàn)程池的執(zhí)行示意圖:

詳細(xì)的執(zhí)行過(guò)程全部在圖中說(shuō)明了。
提交任務(wù)到線(xiàn)程池
在 java 中,有兩個(gè)方法可以將任務(wù)提交到線(xiàn)程池,分別是submit和execute。
execute 方法
execute()方法用于提交不需要返回值的任務(wù),所以無(wú)法判斷任務(wù)是否被線(xiàn)程池執(zhí)行成功。
void execute(Runnable command);
通過(guò)以下代碼可知 execute() 方法輸入的任務(wù)是一個(gè)Runnable類(lèi)的實(shí)例。
executorService.execute(()->{
System.out.println("ThreadPoolDemo.execute");
});
submit 方法
submit()方法用于提交需要返回值的任務(wù)。
Future<?> submit(Runnable task);
線(xiàn)程池會(huì)返回一個(gè)future類(lèi)型的對(duì)象,通過(guò)這個(gè) future 對(duì)象可以判斷任務(wù)是否執(zhí)行成功,并且可以通過(guò)future的get()方法來(lái)獲取返回值,get() 方法會(huì)阻塞當(dāng)前線(xiàn)程直到任務(wù)完成,而使用get(long timeout,TimeUnit unit)方法則會(huì)阻塞當(dāng)前線(xiàn)程一段時(shí)間后立即返回,這時(shí)候有可能任務(wù)沒(méi)有執(zhí)行完。
Future<?> submit = executorService.submit(() -> {
System.out.println("ThreadPoolDemo.submit");
});
關(guān)閉線(xiàn)程池
其實(shí),如果優(yōu)雅的關(guān)閉線(xiàn)程池是一個(gè)令人頭疼的問(wèn)題,線(xiàn)程開(kāi)啟是簡(jiǎn)單的,但是想要停止卻不是那么容易的。通常而言, 大部分程序員都是使用 jdk 提供的兩個(gè)方法來(lái)關(guān)閉線(xiàn)程池,他們分別是:shutdown 或 shutdownNow;
通過(guò)調(diào)用線(xiàn)程池的 shutdown 或 shutdownNow 方法來(lái)關(guān)閉線(xiàn)程池。它們的原理是遍歷線(xiàn)程池中的工作線(xiàn)程,然后逐個(gè)調(diào)用線(xiàn)程的 interrupt 方法來(lái)中斷線(xiàn)程(PS:中斷,僅僅是給線(xiàn)程打上一個(gè)標(biāo)記,并不是代表這個(gè)線(xiàn)程停止了,如果線(xiàn)程不響應(yīng)中斷,那么這個(gè)標(biāo)記將毫無(wú)作用),所以無(wú)法響應(yīng)中斷的任務(wù)可能永遠(yuǎn)無(wú)法終止。
但是它們存在一定的區(qū)別,shutdownNow首先將線(xiàn)程池的狀態(tài)設(shè)置成 STOP,然后嘗試停止所有的正在執(zhí)行或暫停任務(wù)的線(xiàn)程,并返回等待執(zhí)行任務(wù)的列表,而 shutdown 只是將線(xiàn)程池的狀態(tài)設(shè)置成SHUTDOWN狀態(tài),然后中斷所有沒(méi)有正在執(zhí)行任務(wù)的線(xiàn)程。
只要調(diào)用了這兩個(gè)關(guān)閉方法中的任意一個(gè),isShutdown 方法就會(huì)返回 true。當(dāng)所有的任務(wù)都已關(guān)閉后,才表示線(xiàn)程池關(guān)閉成功,這時(shí)調(diào)用isTerminaed方法會(huì)返回 true。至于應(yīng)該調(diào)用哪一種方法來(lái)關(guān)閉線(xiàn)程池,應(yīng)該由提交到線(xiàn)程池的任務(wù)特性決定,通常調(diào)用 shutdown方法來(lái)關(guān)閉線(xiàn)程池,如果任務(wù)不一定要執(zhí)行完,則可以調(diào)用 shutdownNow 方法。
這里推薦使用穩(wěn)妥的 shutdownNow 來(lái)關(guān)閉線(xiàn)程池,至于更優(yōu)雅的方式我會(huì)在以后的并發(fā)編程設(shè)計(jì)模式中的兩階段終止模式中會(huì)再次詳細(xì)介紹。
合理的參數(shù)
為什么叫合理的參數(shù),那不合理的參數(shù)是什么樣子的?在我們創(chuàng)建線(xiàn)程池的時(shí)候,里面的參數(shù)該如何設(shè)置才能稱(chēng)之為合理呢?其實(shí)這是有一定的依據(jù)的,我們先來(lái)看一下以下的創(chuàng)建的方式:
ExecutorService executorService = new ThreadPoolExecutor(5,
5,
5,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(5),
r -> {
Thread thread = new Thread(r);
thread.setName("線(xiàn)程池原理講解");
return thread;
});
你說(shuō)他合理不合理?我也不知道,因?yàn)槲覀儧](méi)有參考的依據(jù),在實(shí)際的開(kāi)發(fā)中,我們需要根據(jù)任務(wù)的性質(zhì)(IO是否頻繁?)來(lái)決定我們創(chuàng)建的核心的線(xiàn)程數(shù)的大小,實(shí)際上可以從以下的一個(gè)角度來(lái)分析:
- 任務(wù)的性質(zhì):CPU密集型任務(wù)、IO密集型任務(wù)和混合型任務(wù);
- 任務(wù)的優(yōu)先級(jí):高、中和低;
- 任務(wù)的執(zhí)行時(shí)間:長(zhǎng)、中和短;
- 任務(wù)的依賴(lài)性:是否依賴(lài)其他系統(tǒng)資源,如數(shù)據(jù)庫(kù)連接;
性質(zhì)不同的任務(wù)可以用不同規(guī)模的線(xiàn)程池分開(kāi)處理。分為CPU密集型和IO密集型。
CPU密集型任務(wù)應(yīng)配置盡可能小的線(xiàn)程,如配置 Ncpu+1個(gè)線(xiàn)程的線(xiàn)程池。(可以通過(guò)Runtime.getRuntime().availableProcessors()來(lái)獲取CPU物理核數(shù))
IO密集型任務(wù)線(xiàn)程并不是一直在執(zhí)行任務(wù),則應(yīng)配置盡可能多的線(xiàn)程,如 2*Ncpu。
混合型的任務(wù),如果可以拆分,將其拆分成一個(gè)CPU密集型任務(wù)一個(gè)IO密集型任務(wù),只要這兩個(gè)任務(wù)執(zhí)行的時(shí)間相差不是太大,那么分解后執(zhí)行的吞吐量將高于串行執(zhí)行的吞吐量。
如果這兩個(gè)任務(wù)執(zhí)行時(shí)間相差太大,則沒(méi)必要進(jìn)行分解。可以通過(guò) Runtime.getRuntime().availableProcessors() 方法獲得當(dāng)前設(shè)備的CPU個(gè)數(shù)。
優(yōu)先級(jí)不同的任務(wù)可以使用優(yōu)先級(jí)隊(duì)列 PriorityBlockingQueue來(lái)處理。它可以讓優(yōu)先級(jí)高的任務(wù)先執(zhí)行(注意:如果一直有優(yōu)先級(jí)高的任務(wù)提交到隊(duì)列里,那么優(yōu)先級(jí)低的任務(wù)可能永遠(yuǎn)不能執(zhí)行)
執(zhí)行時(shí)間不同的任務(wù)可以交給不同規(guī)模的線(xiàn)程池來(lái)處理,或者可以使用優(yōu)先級(jí)隊(duì)列,讓執(zhí)行時(shí)間短的任務(wù)先執(zhí)行。依賴(lài)數(shù)據(jù)庫(kù)連接池的任務(wù),因?yàn)榫€(xiàn)程提交SQL后需要等待數(shù)據(jù)庫(kù)返回結(jié)果,等待的時(shí)間越長(zhǎng),則 CPU 空閑時(shí)間就越長(zhǎng),那么線(xiàn)程數(shù)應(yīng)該設(shè)置得越大,這樣才能更好地利用CPU。
建議使用有界隊(duì)列。有界隊(duì)列能增加系統(tǒng)的穩(wěn)定性和預(yù)警能力,可以根據(jù)需要設(shè)大一點(diǎn)。方式因?yàn)樘峤坏娜蝿?wù)過(guò)多而導(dǎo)致 OOM;
7、本文小結(jié)
本文主要介紹的是線(xiàn)程池的實(shí)現(xiàn)原理以及一些使用技巧,在實(shí)際開(kāi)發(fā)中,線(xiàn)程池可以說(shuō)是稍微高級(jí)一點(diǎn)的程序員的必備技能。所以掌握好線(xiàn)程池這門(mén)技術(shù)也是重中之重!
以上就是深度源碼解析Java 線(xiàn)程池的實(shí)現(xiàn)原理的詳細(xì)內(nèi)容,更多關(guān)于Java 線(xiàn)程池的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
java?webservice超時(shí)時(shí)間設(shè)置方法代碼
當(dāng)我們使用WebService進(jìn)行調(diào)用時(shí),有時(shí)會(huì)出現(xiàn)超時(shí)的情況,下面這篇文章主要給大家介紹了關(guān)于java?webservice超時(shí)時(shí)間設(shè)置方法的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-01-01
Java實(shí)現(xiàn)簡(jiǎn)單郵件發(fā)送
這篇文章主要介紹了Java實(shí)現(xiàn)簡(jiǎn)單郵件發(fā)送的相關(guān)資料,實(shí)例講解了java郵件發(fā)送實(shí)現(xiàn)方法,感興趣的小伙伴們可以參考一下2016-02-02
spring的jdbctemplate的crud的基類(lèi)dao
本文主要介紹了使用spring的jdbctemplate進(jìn)行增刪改查的基類(lèi)Dao的簡(jiǎn)單寫(xiě)法,需要的朋友可以參考下2014-02-02
java設(shè)置session過(guò)期時(shí)間的實(shí)現(xiàn)方法
這篇文章主要介紹了java設(shè)置session過(guò)期時(shí)間的實(shí)現(xiàn)方法,以實(shí)例形式詳細(xì)講述了具體實(shí)現(xiàn)過(guò)程,非常具有參考借鑒價(jià)值,需要的朋友可以參考下2014-10-10
mybatis-plus 攔截器敏感字段加解密的實(shí)現(xiàn)
數(shù)據(jù)庫(kù)在保存數(shù)據(jù)時(shí),對(duì)于某些敏感數(shù)據(jù)需要脫敏或者加密處理,本文主要介紹了mybatis-plus 攔截器敏感字段加解密的實(shí)現(xiàn),感興趣的可以了解一下2021-11-11
Java中l(wèi)ist.foreach不能使用字符串拼接的問(wèn)題
這篇文章主要介紹了Java中l(wèi)ist.foreach不能使用字符串拼接的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
spring boot下mybatis配置雙數(shù)據(jù)源的實(shí)例
這篇文章主要介紹了spring boot下mybatis配置雙數(shù)據(jù)源的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
JAVA得到數(shù)組中最大值和最小值的簡(jiǎn)單實(shí)例
這篇文章主要介紹了JAVA得到數(shù)組中最大值和最小值的簡(jiǎn)單實(shí)例,需要的朋友可以參考下2014-08-08

