高性能必殺技:Java中的池化技術(shù)
共 8384字,需瀏覽 17分鐘
·
2024-05-21 10:30
來(lái)源:juejin.cn/post/7289344148195835961
?? 歡迎加入小哈的星球 ,你將獲得: 專屬的項(xiàng)目實(shí)戰(zhàn) / Java 學(xué)習(xí)路線 / 一對(duì)一提問(wèn) / 學(xué)習(xí)打卡 / 每月贈(zèng)書
新項(xiàng)目:仿小紅書(微服務(wù)架構(gòu))正在更新中... , 全棧前后端分離博客項(xiàng)目 2.0 版本完結(jié)啦, 演示鏈接:http://116.62.199.48/ 。全程手摸手,后端 + 前端全棧開發(fā),從 0 到 1 講解每個(gè)功能點(diǎn)開發(fā)步驟,1v1 答疑,直到項(xiàng)目上線。目前已更新了261小節(jié),累計(jì)41w+字,講解圖:1806張,還在持續(xù)爆肝中.. 后續(xù)還會(huì)上新更多項(xiàng)目,目標(biāo)是將Java領(lǐng)域典型的項(xiàng)目都整一波,如秒殺系統(tǒng), 在線商城, IM即時(shí)通訊,Spring Cloud Alibaba 等等,戳我加入學(xué)習(xí),已有1400+小伙伴加入(早鳥價(jià)超低)
一些廢話
作為一名Java開發(fā)人員,池化技術(shù)或多或少在業(yè)務(wù)代碼中使用。常見的包括線程池、連接池等。也是因?yàn)镴ava語(yǔ)言超級(jí)豐富的基建,基本上這些池化能力都有著相對(duì)成熟的“工具”。
比如,需要使用線程池的時(shí)候常常會(huì)選擇Spring提供的 ThreadPoolTaskExecutor,工具內(nèi)部替我們維護(hù)了線程的生命周期與任務(wù)的狀態(tài)變化。
線程池的運(yùn)轉(zhuǎn)流程圖
正文開始
在筆者的業(yè)務(wù)場(chǎng)景里,java服務(wù)需要通過(guò)命令行啟動(dòng)一個(gè)特殊進(jìn)程,并在進(jìn)程使用完后將其銷毀。而業(yè)務(wù)對(duì)啟動(dòng)這個(gè)進(jìn)程的整體耗時(shí)較為敏感,打算利用池化技術(shù),將進(jìn)程池化復(fù)用,去除啟動(dòng)進(jìn)程的消耗,達(dá)到優(yōu)化性能的目標(biāo)。
認(rèn)識(shí) GenericObjectPool
池化技術(shù)的概念大家可能都比較熟悉了,但真正要從零開始實(shí)現(xiàn)池化能力,就會(huì)感覺困難很多。好在Java豐富的基建在提供ThreadPoolTaskExecutor的同時(shí),也提供了GenericObjectPool這個(gè)輔助我們實(shí)現(xiàn)自定義對(duì)象池化的工具。
順帶提一句,JedisPool就是使用這個(gè)工具實(shí)現(xiàn)的。
GenericObjectPool構(gòu)造方法一共就3個(gè)參數(shù),只有PooledObjectFactory必傳;
/**
* Creates a new {@code GenericObjectPool} that tracks and destroys
* objects that are checked out, but never returned to the pool.
*
* @param factory The object factory to be used to create object instances
* used by this pool
* @param config The base pool configuration to use for this pool instance.
* The configuration is used by value. Subsequent changes to
* the configuration object will not be reflected in the
* pool.
* @param abandonedConfig Configuration for abandoned object identification
* and removal. The configuration is used by value.
*/
public GenericObjectPool(final PooledObjectFactory<T> factory,
final GenericObjectPoolConfig<T> config, final AbandonedConfig abandonedConfig) {
}
PooledObjectFactory 按照方法注釋的描述,它是專門負(fù)責(zé)給池子創(chuàng)建對(duì)象實(shí)例的。當(dāng)然除了創(chuàng)建對(duì)象(makeObject),還包括了檢驗(yàn)、激活、銷毀對(duì)象?;竞w了對(duì)象生命周期中的各個(gè)階段。
void activateObject(PooledObject<T> p) throws Exception;
void destroyObject(PooledObject<T> p) throws Exception;
PooledObject<T> makeObject() throws Exception;
void passivateObject(PooledObject<T> p) throws Exception;
boolean validateObject(PooledObject<T> p);
更加詳細(xì)的說(shuō)明可以瀏覽 GenericObjectPool's apidocs。源碼的注釋也很詳細(xì)值得一看。
使用 GenericObjectPool
先引入依賴
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>${version}</version>
</dependency>
根據(jù)自身業(yè)務(wù)實(shí)現(xiàn)PooledObjectFactory接口;作者的業(yè)務(wù)場(chǎng)景是進(jìn)程池化,那么對(duì)應(yīng)的創(chuàng)建對(duì)象、銷毀對(duì)象的方法就是創(chuàng)建進(jìn)程和銷毀進(jìn)程的代碼。
public class MyProcessFactory implements PooledObjectFactory<MyProcess> {
@Override
public void destroyObject(PooledObject<MyProcess> p) throws Exception {
final MyProcess process = p.getObject();
if (null != process) {
// 銷毀進(jìn)程
process.stop();
}
}
@Override
public PooledObject<MyProcess> makeObject() throws Exception {
// 這里就是去創(chuàng)建一個(gè)進(jìn)程
MyProcess process = new MyProcess();
process.start();
return new DefaultPooledObject<>(process);
}
// 剩下幾個(gè)方法也可以按需實(shí)現(xiàn)
}
下一步就是構(gòu)建 GenericObjectPool 實(shí)例
PooledObjectFactory<MyProcess> factory = new MyProcessFactory();
GenericObjectPool<MyProcess> pool = new GenericObjectPool(factory);
使用GenericObjectPool
// 獲取進(jìn)程實(shí)例
MyProcess process = pool.borrowObject();
// 歸還實(shí)例
pool.returnObject(process);
進(jìn)階使用 GenericObjectPoolConfig
顧名思義,GenericObjectPoolConfig是池化工具的配置類;它包含了池的最大容量、池的最大空閑數(shù)、最小空閑數(shù)等核心參數(shù)。除此之外在它的父類 BaseObjectPoolConfig 中,空閑對(duì)象檢測(cè)規(guī)則,對(duì)象存放隊(duì)列進(jìn)出規(guī)則(LIFO)等更加細(xì)節(jié)的配置。
/**
* The default value for the {@code maxTotal} configuration attribute.
* @see GenericObjectPool#getMaxTotal()
*/
public static final int DEFAULT_MAX_TOTAL = 8;
/**
* The default value for the {@code maxIdle} configuration attribute.
* @see GenericObjectPool#getMaxIdle()
*/
public static final int DEFAULT_MAX_IDLE = 8;
/**
* The default value for the {@code minIdle} configuration attribute.
* @see GenericObjectPool#getMinIdle()
*/
public static final int DEFAULT_MIN_IDLE = 0;
通過(guò)調(diào)整這些參數(shù)值,就能創(chuàng)建符合業(yè)務(wù)要求的池子。下面就是能常駐4個(gè)進(jìn)程的一套配置參數(shù)。
private GenericObjectPoolConfig<MyProcess> genericObjectPoolConfig() {
final GenericObjectPoolConfig<MyProcess> config = new GenericObjectPoolConfig<>();
config.setMaxTotal(20); // 池的最大容量
config.setMaxIdle(4); // 最大空閑連接數(shù)
config.setMinIdle(0); // 最小空閑連接數(shù)
config.setMaxWait(Duration.ofSeconds(5)); // 獲取對(duì)象時(shí)最大等待時(shí)間
config.setTimeBetweenEvictionRuns(Duration.ofMinutes(1)); // 空閑對(duì)象檢查間隔
config.setMinEvictableIdleTime(Duration.ofMinutes(10)); // 空閑對(duì)象被移除的最小空閑時(shí)間
config.setTestOnBorrow(true);
config.setLifo(false);
return config;
}
后續(xù)
當(dāng)然真實(shí)的業(yè)務(wù)中還會(huì)有很多不相關(guān)的邏輯夾雜其中,上文基本涵蓋了池化對(duì)象搭建與配置的實(shí)現(xiàn)方法。最終也實(shí)現(xiàn)了性能優(yōu)化的目標(biāo)。希望此文能為大家在池化運(yùn)用多些幫助。
?? 歡迎加入小哈的星球 ,你將獲得: 專屬的項(xiàng)目實(shí)戰(zhàn) / Java 學(xué)習(xí)路線 / 一對(duì)一提問(wèn) / 學(xué)習(xí)打卡 / 每月贈(zèng)書
新項(xiàng)目:仿小紅書(微服務(wù)架構(gòu))正在更新中... , 全棧前后端分離博客項(xiàng)目 2.0 版本完結(jié)啦, 演示鏈接:http://116.62.199.48/ 。全程手摸手,后端 + 前端全棧開發(fā),從 0 到 1 講解每個(gè)功能點(diǎn)開發(fā)步驟,1v1 答疑,直到項(xiàng)目上線。目前已更新了261小節(jié),累計(jì)41w+字,講解圖:1806張,還在持續(xù)爆肝中.. 后續(xù)還會(huì)上新更多項(xiàng)目,目標(biāo)是將Java領(lǐng)域典型的項(xiàng)目都整一波,如秒殺系統(tǒng), 在線商城, IM即時(shí)通訊,Spring Cloud Alibaba 等等,戳我加入學(xué)習(xí),已有1400+小伙伴加入(早鳥價(jià)超低)
2. 官方推出了 Spring AI 框架,Java集成 AI 不再是難事!
最近面試BAT,整理一份面試資料《Java面試BATJ通關(guān)手冊(cè)》,覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務(wù)、數(shù)據(jù)庫(kù)、數(shù)據(jù)結(jié)構(gòu)等等。
獲取方式:點(diǎn)“在看”,關(guān)注公眾號(hào)并回復(fù) Java 領(lǐng)取,更多內(nèi)容陸續(xù)奉上。
PS:因公眾號(hào)平臺(tái)更改了推送規(guī)則,如果不想錯(cuò)過(guò)內(nèi)容,記得讀完點(diǎn)一下“在看”,加個(gè)“星標(biāo)”,這樣每次新文章推送才會(huì)第一時(shí)間出現(xiàn)在你的訂閱列表里。
點(diǎn)“在看”支持小哈呀,謝謝啦
