1 一些廢話
作為一名Java開發人員,池化技術或多或少在業務代碼中使用。常見的包括線程池、連接池等。也是因為Java語言超級豐富的基建,基本上這些池化能力都有著相對成熟的“工具”。
比如,需要使用線程池的時候常常會選擇Spring提供的 ThreadPoolTaskExecutor , 工具內部替我們維護了線程的生命周期與任務的狀態變化。
線程池的運轉流程圖
2 正文開始
在筆者的業務場景里,java服務需要通過命令行啟動一個特殊進程,并在進程使用完后將其銷毀。而業務對啟動這個進程的整體耗時較為敏感,打算利用池化技術,將進程池化復用,去除啟動進程的消耗,達到優化性能的目標。
認識 GenericObjectPool
池化技術的概念大家可能都比較熟悉了,但真正要從零開始實現池化能力,就會感覺困難很多。好在Java豐富的基建在提供ThreadPoolTaskExecutor的同時,也提供了GenericObjectPool這個輔助我們實現自定義對象池化的工具。順帶提一句:JedisPool就是使用這個工具實現的。
GenericObjectPool構造方法一共就3個參數,只有PooledObjectFactory必傳;
/** *Createsanew{@codeGenericObjectPool}thattracksanddestroys *objectsthatarecheckedout,butneverreturnedtothepool. * *@paramfactoryTheobjectfactorytobeusedtocreateobjectinstances *usedbythispool *@paramconfigThebasepoolconfigurationtouseforthispoolinstance. *Theconfigurationisusedbyvalue.Subsequentchangesto *theconfigurationobjectwillnotbereflectedinthe *pool. *@paramabandonedConfigConfigurationforabandonedobjectidentification *andremoval.Theconfigurationisusedbyvalue. */ publicGenericObjectPool(finalPooledObjectFactoryfactory, finalGenericObjectPoolConfig config,finalAbandonedConfigabandonedConfig){ }
PooledObjectFactory 按照方法注釋的描述,它是專門負責給池子創建對象實例的。當然除了創建對象(makeObject), 還包括了檢驗、激活、銷毀對象。基本涵蓋了對象生命周期中的各個階段。
voidactivateObject(PooledObjectp)throwsException; voiddestroyObject(PooledObject p)throwsException; PooledObject makeObject()throwsException; voidpassivateObject(PooledObject p)throwsException; booleanvalidateObject(PooledObject p);
更加詳細的說明可以瀏覽 GenericObjectPool's apidocs [1]。源碼的注釋也很詳細值得一看。
使用 GenericObjectPool
先引入依賴
org.apache.commons commons-pool2 ${version}
根據自身業務實現PooledObjectFactory接口;作者的業務場景是進程池化,那么對應的創建對象、銷毀對象的方法就是創建進程和銷毀進程的代碼。
publicclassMyProcessFactoryimplementsPooledObjectFactory{ @Override publicvoiddestroyObject(PooledObject p)throwsException{ finalMyProcessprocess=p.getObject(); if(null!=process){ //銷毀進程 process.stop(); } } @Override publicPooledObject makeObject()throwsException{ //這里就是去創建一個進程 MyProcessprocess=newMyProcess(); process.start(); returnnewDefaultPooledObject<>(process); } //剩下幾個方法也可以按需實現 }
下一步就是構建 GenericObjectPool 實例
PooledObjectFactoryfactory=newMyProcessFactory(); GenericObjectPool pool=newGenericObjectPool(factory);
使用GenericObjectPool
//獲取進程實例 MyProcessprocess=pool.borrowObject(); //歸還實例 pool.returnObject(process);
進階使用 GenericObjectPoolConfig
顧名思義,GenericObjectPoolConfig是池化工具的配置類;它包含了池的最大容量、池的最大空閑數、最小空閑數等核心參數。除此之外在它的父類 BaseObjectPoolConfig 中,空閑對象檢測規則,對象存放隊列進出規則(LIFO)等更加細節的配置。
/** *Thedefaultvalueforthe{@codemaxTotal}configurationattribute. *@seeGenericObjectPool#getMaxTotal() */ publicstaticfinalintDEFAULT_MAX_TOTAL=8; /** *Thedefaultvalueforthe{@codemaxIdle}configurationattribute. *@seeGenericObjectPool#getMaxIdle() */ publicstaticfinalintDEFAULT_MAX_IDLE=8; /** *Thedefaultvalueforthe{@codeminIdle}configurationattribute. *@seeGenericObjectPool#getMinIdle() */ publicstaticfinalintDEFAULT_MIN_IDLE=0;
通過調整這些參數值,就能創建符合業務要求的池子。下面就是能常駐4個進程的一套配置參數。
privateGenericObjectPoolConfiggenericObjectPoolConfig(){ finalGenericObjectPoolConfig config=newGenericObjectPoolConfig<>(); config.setMaxTotal(20);//池的最大容量 config.setMaxIdle(4);//最大空閑連接數 config.setMinIdle(0);//最小空閑連接數 config.setMaxWait(Duration.ofSeconds(5));//獲取對象時最大等待時間 config.setTimeBetweenEvictionRuns(Duration.ofMinutes(1));//空閑對象檢查間隔 config.setMinEvictableIdleTime(Duration.ofMinutes(10));//空閑對象被移除的最小空閑時間 config.setTestOnBorrow(true); config.setLifo(false); returnconfig; }
3 后續
當然真實的業務中還會有很多不相關的邏輯夾雜其中,上文基本涵蓋了池化對象搭建與配置的實現方法。最終也實現了性能優化的目標。希望此文能為大家在池化運用多些幫助。
-
JAVA
+關注
關注
19文章
2966瀏覽量
104702 -
線程池
+關注
關注
0文章
57瀏覽量
6844 -
命令行
+關注
關注
0文章
77瀏覽量
10385 -
池化
+關注
關注
0文章
4瀏覽量
1100
發布評論請先 登錄
相關推薦
評論