1 一些廢話
作為一名Java開發(fā)人員,池化技術(shù)或多或少在業(yè)務(wù)代碼中使用。常見的包括線程池、連接池等。也是因為Java語言超級豐富的基建,基本上這些池化能力都有著相對成熟的“工具”。
比如,需要使用線程池的時候常常會選擇Spring提供的 ThreadPoolTaskExecutor , 工具內(nèi)部替我們維護了線程的生命周期與任務(wù)的狀態(tài)變化。
線程池的運轉(zhuǎn)流程圖
2 正文開始
在筆者的業(yè)務(wù)場景里,java服務(wù)需要通過命令行啟動一個特殊進程,并在進程使用完后將其銷毀。而業(yè)務(wù)對啟動這個進程的整體耗時較為敏感,打算利用池化技術(shù),將進程池化復(fù)用,去除啟動進程的消耗,達到優(yōu)化性能的目標。
認識 GenericObjectPool
池化技術(shù)的概念大家可能都比較熟悉了,但真正要從零開始實現(xiàn)池化能力,就會感覺困難很多。好在Java豐富的基建在提供ThreadPoolTaskExecutor的同時,也提供了GenericObjectPool這個輔助我們實現(xiàn)自定義對象池化的工具。順帶提一句:JedisPool就是使用這個工具實現(xiàn)的。
GenericObjectPool構(gòu)造方法一共就3個參數(shù),只有PooledObjectFactory必傳;
/** *Createsanew{@codeGenericObjectPool}thattracksanddestroys *objectsthatarecheckedout,butneverreturnedtothepool. * *@paramfactoryTheobjectfactorytobeusedtocreateobjectinstances *usedbythispool *@paramconfigThebasepoolconfigurationtouseforthispoolinstance. *Theconfigurationisusedbyvalue.Subsequentchangesto *theconfigurationobjectwillnotbereflectedinthe *pool. *@paramabandonedConfigConfigurationforabandonedobjectidentification *andremoval.Theconfigurationisusedbyvalue. */ publicGenericObjectPool(finalPooledObjectFactoryfactory, finalGenericObjectPoolConfig config,finalAbandonedConfigabandonedConfig){ }
PooledObjectFactory 按照方法注釋的描述,它是專門負責(zé)給池子創(chuàng)建對象實例的。當(dāng)然除了創(chuàng)建對象(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}
根據(jù)自身業(yè)務(wù)實現(xiàn)PooledObjectFactory接口;作者的業(yè)務(wù)場景是進程池化,那么對應(yīng)的創(chuàng)建對象、銷毀對象的方法就是創(chuàng)建進程和銷毀進程的代碼。
publicclassMyProcessFactoryimplementsPooledObjectFactory{ @Override publicvoiddestroyObject(PooledObject p)throwsException{ finalMyProcessprocess=p.getObject(); if(null!=process){ //銷毀進程 process.stop(); } } @Override publicPooledObject makeObject()throwsException{ //這里就是去創(chuàng)建一個進程 MyProcessprocess=newMyProcess(); process.start(); returnnewDefaultPooledObject<>(process); } //剩下幾個方法也可以按需實現(xiàn) }
下一步就是構(gòu)建 GenericObjectPool 實例
PooledObjectFactoryfactory=newMyProcessFactory(); GenericObjectPool pool=newGenericObjectPool(factory);
使用GenericObjectPool
//獲取進程實例 MyProcessprocess=pool.borrowObject(); //歸還實例 pool.returnObject(process);
進階使用 GenericObjectPoolConfig
顧名思義,GenericObjectPoolConfig是池化工具的配置類;它包含了池的最大容量、池的最大空閑數(shù)、最小空閑數(shù)等核心參數(shù)。除此之外在它的父類 BaseObjectPoolConfig 中,空閑對象檢測規(guī)則,對象存放隊列進出規(guī)則(LIFO)等更加細節(jié)的配置。
/** *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;
通過調(diào)整這些參數(shù)值,就能創(chuàng)建符合業(yè)務(wù)要求的池子。下面就是能常駐4個進程的一套配置參數(shù)。
privateGenericObjectPoolConfiggenericObjectPoolConfig(){ finalGenericObjectPoolConfig config=newGenericObjectPoolConfig<>(); config.setMaxTotal(20);//池的最大容量 config.setMaxIdle(4);//最大空閑連接數(shù) config.setMinIdle(0);//最小空閑連接數(shù) config.setMaxWait(Duration.ofSeconds(5));//獲取對象時最大等待時間 config.setTimeBetweenEvictionRuns(Duration.ofMinutes(1));//空閑對象檢查間隔 config.setMinEvictableIdleTime(Duration.ofMinutes(10));//空閑對象被移除的最小空閑時間 config.setTestOnBorrow(true); config.setLifo(false); returnconfig; }
3 后續(xù)
當(dāng)然真實的業(yè)務(wù)中還會有很多不相關(guān)的邏輯夾雜其中,上文基本涵蓋了池化對象搭建與配置的實現(xiàn)方法。最終也實現(xiàn)了性能優(yōu)化的目標。希望此文能為大家在池化運用多些幫助。
審核編輯:黃飛
-
JAVA
+關(guān)注
關(guān)注
19文章
2966瀏覽量
104702 -
編程語言
+關(guān)注
關(guān)注
10文章
1942瀏覽量
34707 -
線程池
+關(guān)注
關(guān)注
0文章
57瀏覽量
6844
原文標題:池化技術(shù)在真實業(yè)務(wù)中的實踐
文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論