游戏电视苹果数码历史美丽
投稿投诉
美丽时装
彩妆资讯
历史明星
乐活安卓
数码常识
驾车健康
苹果问答
网络发型
电视车载
室内电影
游戏科学
音乐整形

Java中的对象池实现

  最近在分析一个应用中的某个接口的耗时情况时,发现一个看起来极其普通的对象创建操作,竟然每次需要消耗8ms左右时间,分析后发现这个对象可以通过对象池模式进行优化,优化后此步耗时仅有0。01ms,这篇文章介绍对象池相关知识。
  1。什么是对象池
  池化并不是什么新鲜的技术,它更像一种软件设计模式,主要功能是缓存一组已经初始化的对象,以供随时可以使用。对象池大多数场景下都是缓存着创建成本过高或者需要重复创建使用的对象,从池子中取出对象的时间是可以预测的,但是新建一个对象的时间是不确定的。
  当需要一个新对象时,就向池中借出一个,然后对象池标记当前对象正在使用,使用完毕后归还到对象池,以便再次借出。
  常见的使用对象池化的场景:对象创建成本过高。需要频繁地创建大量重复对象,会产生很多内存碎片。同时使用的对象也不会太多。常见的具体场景如数据库连接池、线程池等。2。为什么需要对象池
  如果一个对象的创建成本很高,比如建立数据库的连接时耗时过长,在不使用池化技术的情况下,我们的查询过程可能是这样的。查询1:建立数据库连接发起查询收到响应关闭连接查询2:建立数据库连接发起查询收到响应关闭连接查询3:建立数据库连接发起查询收到响应关闭连接
  在这种模式下,每次查询都要重新建立关闭连接,因为建立连接是一个耗时的操作,所以这种模式会影响程序的总体性能。
  那么使用池化思想是怎么样的呢?同样的过程也会转变成下面的步骤。初始化:建立N个数据库连接缓存起来查询1:从缓存借到数据库连接发起查询收到响应归还数据库连接对象到缓存查询2:从缓存借到数据库连接发起查询收到响应归还数据库连接对象到缓存查询3:从缓存借到数据库连接发起查询收到响应归还数据库连接对象到缓存
  使用池化思想后,数据库连接并不会频繁地创建关闭,而是启动后就初始化了N连接以供后续使用,使用完毕后归还对象,这样程序的总体性能得到提升。3。对象池的实现
  通过上面的例子也可以发现池化思想的几个关键步骤:初始化、借出、归还。上面没有展示销毁步骤,某些场景下还需要对象地销毁这一过程,比如释放连接。
  下面我们手动实现一个简陋的对象池,加深下对对象池的理解。主要是定一个对象池管理类,然后在里面实现对象的初始化、借出、归还、销毁等操作。packagecom。wdbyet。tool。objectpool。mypool;importjava。io。Closeable;importjava。io。IOException;importjava。util。HashSet;importjava。util。Stack;authorhttps:www。wdbyte。compublicclassMyObjectPoolTextendsCloseable{池子大小privateIntegersize5;对象池栈。后进先出privateStackTstackPoolnewStack();借出的对象的hashCode集合privateHashSetIntegerborrowHashCodeSetnewHashSet();增加一个对象paramtpublicsynchronizedvoidaddObj(Tt){if((stackPool。size()borrowHashCodeSet。size())size){thrownewRuntimeException(池中对象已经达到最大值);}stackPool。add(t);System。out。println(添加了对象:t。hashCode());}借出一个对象returnpublicsynchronizedTborrowObj(){if(stackPool。isEmpty()){System。out。println(没有可以被借出的对象);returnnull;}TpopstackPool。pop();borrowHashCodeSet。add(pop。hashCode());System。out。println(借出了对象:pop。hashCode());returnpop;}归还一个对象paramtpublicsynchronizedvoidreturnObj(Tt){if(borrowHashCodeSet。contains(t。hashCode())){stackPool。add(t);borrowHashCodeSet。remove(t。hashCode());System。out。println(归还了对象:t。hashCode());return;}thrownewRuntimeException(只能归还从池中借出的对象);}销毁池中对象publicsynchronizedvoiddestory(){if(!borrowHashCodeSet。isEmpty()){thrownewRuntimeException(尚有未归还的对象,不能关闭所有对象);}while(!stackPool。isEmpty()){TpopstackPool。pop();try{pop。close();}catch(IOExceptione){thrownewRuntimeException(e);}}System。out。println(已经销毁了所有对象);}}折叠
  代码还是比较简单的,只是简单的示例,下面我们通过池化一个Redis连接对象Jedis来演示如何使用。
  其实Jedis中已经有对应的Jedis池化管理对象了JedisPool了,不过我们这里为了演示对象池的实现,就不使用官方提供的JedisPool了。
  启动一个Redis服务这里不做介绍,假设你已经有了一个Redis服务,下面引入Java中连接Redis需要用到的Maven依赖。dependencygroupIdredis。clientsgroupIdjedisartifactIdversion4。2。0versiondependency
  正常情况下Jedis对象的使用方式:JedisjedisnewJedis(localhost,6379);Stringnamejedis。get(name);System。out。println(name);jedis。close();
  如果使用上面的对象池,就可以像下面这样使用。packagecom。wdbyet。tool。objectpool。mypool;importredis。clients。jedis。Jedis;authorniulangdate20220702publicclassMyObjectPoolTest{publicstaticvoidmain(String〔〕args){MyObjectPoolJedisobjectPoolnewMyObjectPool();增加一个jedis连接对象objectPool。addObj(newJedis(127。0。0。1,6379));objectPool。addObj(newJedis(127。0。0。1,6379));从对象池中借出一个jedis对象JedisjedisobjectPool。borrowObj();一次redis查询Stringnamejedis。get(name);System。out。println(String。format(redisget:name));归还redis连接对象objectPool。returnObj(jedis);销毁对象池中的所有对象objectPool。destory();再次借用对象objectPool。borrowObj();}}
  输出日志:添加了对象:1556956098添加了对象:1252585652借出了对象:1252585652redisget:www。wdbyte。com归还了对象:1252585652已经销毁了所有对象没有可以被借出的对象
  如果使用JMH对使用对象池化进行Redis查询,和正常创建Redis连接然后查询关闭连接的方式进行性能对比,会发现两者的性能差异很大。下面是测试结果,可以发现使用对象池化后的性能是非池化方式的5倍左右。BenchmarkModeCntScoreErrorUnitsMyObjectPoolTest。testthrpt152612。689358。767opssMyObjectPoolTest。testPoolthrpt912414。22811669。484opss4。开源的对象池工具
  上面自己实现的对象池总归有些简陋了,其实开源工具中已经有了非常好用的对象池的实现,如Apache的commonspool2工具,很多开源工具中的对象池都是基于此工具实现,下面介绍这个工具的使用方式。
  maven依赖:dependencygroupIdorg。apache。commonsgroupIdcommonspool2artifactIdversion2。11。1versiondependency
  在commonspool2对象池工具中有几个关键的类。PooledObjectFactory类是一个工厂接口,用于实现想要池化对象的创建、验证、销毁等操作。GenericObjectPool类是一个通用的对象池管理类,可以进行对象的借出、归还等操作。GenericObjectPoolConfig类是对象池的配置类,可以进行对象的最大、最小等容量信息进行配置。
  下面通过一个具体的示例演示commonspool2工具类的使用,这里依旧选择Redis连接对象Jedis作为演示。
  实现PooledObjectFactory工厂类,实现其中的对象创建和销毁方法。publicclassMyPooledObjectFactoryimplementsPooledObjectFactoryJedis{OverridepublicvoidactivateObject(PooledObjectJedispooledObject)throwsException{}OverridepublicvoiddestroyObject(PooledObjectJedispooledObject)throwsException{JedisjedispooledObject。getObject();jedis。close();System。out。println(释放连接);}OverridepublicPooledObjectJedismakeObject()throwsException{returnnewDefaultPooledObject(newJedis(localhost,6379));}OverridepublicvoidpassivateObject(PooledObjectJedispooledObject)throwsException{}OverridepublicbooleanvalidateObject(PooledObjectJedispooledObject){returnfalse;}}
  继承GenericObjectPool类,实现对对象的借出、归还等操作。publicclassMyGenericObjectPoolextendsGenericObjectPoolJedis{publicMyGenericObjectPool(PooledObjectFactoryfactory){super(factory);}publicMyGenericObjectPool(PooledObjectFactoryfactory,GenericObjectPoolConfigconfig){super(factory,config);}publicMyGenericObjectPool(PooledObjectFactoryfactory,GenericObjectPoolConfigconfig,AbandonedConfigabandonedConfig){super(factory,config,abandonedConfig);}}
  可以看到MyGenericObjectPool类的构造函数中的入参有GenericObjectPoolConfig对象,这是个对象池的配置对象,可以配置对象池的容量大小等信息,这里就不配置了,使用默认配置。
  通过GenericObjectPoolConfig的源码可以看到默认配置中,对象池的容量是8个。publicclassGenericObjectPoolConfigTextendsBaseObjectPoolConfigT{Thedefaultvalueforthe{codemaxTotal}configurationattribute。seeGenericObjectPoolgetMaxTotal()publicstaticfinalintDEFAULTMAXTOTAL8;Thedefaultvalueforthe{codemaxIdle}configurationattribute。seeGenericObjectPoolgetMaxIdle()publicstaticfinalintDEFAULTMAXIDLE8;
  下面编写一个对象池使用测试类。publicclassApachePool{publicstaticvoidmain(String〔〕args)throwsException{MyGenericObjectPoolobjectMyObjectPoolnewMyGenericObjectPool(newMyPooledObjectFactory());JedisjedisobjectMyObjectPool。borrowObject();Stringnamejedis。get(name);System。out。println(name);objectMyObjectPool。returnObject(jedis);objectMyObjectPool。close();}}
  输出日志:redisget:www。wdbyte。com释放连接
  上面已经演示了commonspool2工具中的对象池的使用方式,从上面的例子中可以发现这种对象池中只能存放同一种初始化条件的对象,如果这里的Redis我们需要存储一个本地连接和一个远程连接的两种Jedis对象,就不能满足了。那么怎么办呢?
  其实commonspool2工具已经考虑到了这种情况,通过增加一个key值可以在同一个对象池管理中进行区分,代码和上面类似,直接贴出完整的代码实现。packagecom。wdbyet。tool。objectpool。apachekeyedpool;importorg。apache。commons。pool2。BaseKeyedPooledObjectFactory;importorg。apache。commons。pool2。KeyedPooledObjectFactory;importorg。apache。commons。pool2。PooledObject;importorg。apache。commons。pool2。impl。AbandonedConfig;importorg。apache。commons。pool2。impl。DefaultPooledObject;importorg。apache。commons。pool2。impl。GenericKeyedObjectPool;importorg。apache。commons。pool2。impl。GenericKeyedObjectPoolConfig;importredis。clients。jedis。Jedis;authorhttps:www。wdbyte。comdate20220707publicclassApacheKeyedPool{publicstaticvoidmain(String〔〕args)throwsException{Stringkeylocal;MyGenericKeyedObjectPoolobjectMyObjectPoolnewMyGenericKeyedObjectPool(newMyKeyedPooledObjectFactory());JedisjedisobjectMyObjectPool。borrowObject(key);Stringnamejedis。get(name);System。out。println(redisget:name);objectMyObjectPool。returnObject(key,jedis);}}classMyKeyedPooledObjectFactoryextendsBaseKeyedPooledObjectFactoryString,Jedis{OverridepublicJediscreate(Stringkey)throwsException{if(local。equals(key)){returnnewJedis(localhost,6379);}if(remote。equals(key)){returnnewJedis(192。168。0。105,6379);}returnnull;}OverridepublicPooledObjectJediswrap(Jedisvalue){returnnewDefaultPooledObject(value);}}classMyGenericKeyedObjectPoolextendsGenericKeyedObjectPoolString,Jedis{publicMyGenericKeyedObjectPool(KeyedPooledObjectFactoryString,Jedisfactory){super(factory);}publicMyGenericKeyedObjectPool(KeyedPooledObjectFactoryString,Jedisfactory,GenericKeyedObjectPoolConfigJedisconfig){super(factory,config);}publicMyGenericKeyedObjectPool(KeyedPooledObjectFactoryString,Jedisfactory,GenericKeyedObjectPoolConfigJedisconfig,AbandonedConfigabandonedConfig){super(factory,config,abandonedConfig);}}折叠
  输出日志:redisget:www。wdbyte。com5。JedisPool对象池实现分析
  这篇文章中的演示都使用了Jedis连接对象,其实在JedisSDK中已经实现了相应的对象池,也就是我们常用的JedisPool类。那么这里的JedisPool是怎么实现的呢?我们先看一下JedisPool的使用方式。packagecom。wdbyet。tool。objectpool;importredis。clients。jedis。Jedis;importredis。clients。jedis。JedisPool;authorhttps:www。wdbyte。compublicclassJedisPoolTest{publicstaticvoidmain(String〔〕args){JedisPooljedisPoolnewJedisPool(localhost,6379);从对象池中借一个对象JedisjedisjedisPool。getResource();Stringnamejedis。get(name);System。out。println(redisget:name);jedis。close();彻底退出前,关闭Redis连接池jedisPool。close();}}
  代码中添加了注释,可以看到通过jedisPool。getResource()拿到了一个对象,这里和上面commonspool2工具中的borrowObject十分相似,继续追踪它的代码实现可以看到下面的代码。redis。clients。jedis。JedisPoolpublicclassJedisPoolextendsPoolJedis{publicJedisgetResource(){Jedisjedis(Jedis)super。getResource();jedis。setDataSource(this);returnjedis;}继续追踪super。getResource()redis。clients。jedis。util。PoolpublicTgetResource(){try{returnsuper。borrowObject();}catch(JedisExceptionvar2){throwvar2;}catch(Exceptionvar3){thrownewJedisException(Couldnotgetaresourcefromthepool,var3);}}
  竟然看到了super。borrowObject(),多么熟悉的方法,继续分析代码可以发现Jedis对象池也是适用了commonspool2工具作为实现。既然如此,那么jedis。close()方法的逻辑我们应该也可以猜到了,应该有一个归还的操作,查看代码发现果然如此。redis。clients。jedis。JedisPoolpublicclassJedisPoolextendsPoolJedis{publicvoidclose(){if(this。dataSource!null){PoolJedispoolthis。dataSource;this。dataSourcenull;if(this。isBroken()){pool。returnBrokenResource(this);}else{pool。returnResource(this);}}else{this。connection。close();}}继续追踪super。getResource()redis。clients。jedis。util。PoolpublicvoidreturnResource(Tresource){if(resource!null){try{super。returnObject(resource);}catch(RuntimeExceptionvar3){thrownewJedisException(Couldnotreturntheresourcetothepool,var3);}}}
  通过上面的分析,可见Jedis确实使用了commonspool2工具进行对象池的管理,通过分析JedisPool类的继承关系图也可以发现。
  6。对象池总结
  通过这篇文章的介绍,可以发现池化思想有几个明显的优势。可以显著的提高应用程序的性能。如果一个对象创建成本过高,那么使用池化非常有效。池化提供了一种对象的管理以及重复使用的方式,减少内存碎片。可以为对象的创建数量提供限制,对某些对象不能创建过多的场景提供保护。
  但是使用对象池化也有一些需要注意的地方,比如归还对象时应确保对象已经被重置为可以重复使用的状态。同时也要注意,使用池化时要根据具体的场景合理的设置池子的大小,过小达不到想要的效果,过大会造成内存浪费。
  一如既往,文章中代码存放在Github。comniumoojavaNotes。
  原文链接:https:www。cnblogs。comniumoop16472756。html

电热毯平常不开就垫着可以吗电热毯关了还有辐射吗在我们平时生活中,很多人冬天都会用电热毯,电热毯是铺在床垫和床单中间的,电热毯平时不用的时候也可以铺在床上,只要不打开电源就好了。电热毯平常不开就垫着可以吗电热毯平时不开……惠州行记2022第三只眼看大湾区过年的九天假,只有第一天除夕夜是全天待在家里的。初一逛街,买了一件西服外套和一条云朵似的围巾。初二至初六跟随公婆走亲戚,如同巨婴一般,……戴隐形眼镜能炒菜吗戴隐形眼镜这样炒菜在我们平时生活中,很多人都会戴隐形眼镜,隐形眼镜是现在很常见的一种眼镜,我们平时炒菜的时候会有很多高温的油脂和颗粒物质,那么戴隐形眼镜能炒菜吗?戴隐形眼镜这样炒菜。戴隐形眼镜能……产品100倒角环,算是黑科技?封面1产品100计划自从切削之家账号建立以来,我们就一直聚焦在刀具上,各品牌刀具的特点,品牌的渠道,我们会尽其所能帮助粉丝或者企业主找到合适的解决方案,所有的解决方……炒股不赚钱,你来找我若是炒股不赚钱,你来找我给你赔钱那是不可能,但是我能让你坚持有信心继续干下去,直到财务自由,至少也要混个中产。若是炒股看那些财经新闻,奥迪进去奥妙出来,若是看炒股看研报,看公司……日本一美女主播转型基金经理,击败97同行!选股与巴菲特雷同宏观事件风起云涌的2022年,将一众擅长把握国际宏观策略的中生代基金经理推上了历史舞台的中央。在全球第三大股票市场日本,一名基金经理正因为优秀的成绩和独特的经历引发舆论关注。……峪藏菜根谈2023年1月21日,星期六,壬寅年农历腊月三十(己卯日)除夕快乐!峪藏菜根谈1、世卫组织研究:感染新冠并接种疫苗产生的混合免疫保护效果可持续至少1年。2、电影院线……珍视明滴眼液可以长期使用吗珍视明滴眼液可以滴隐形眼镜吗珍视明滴眼液是我们大家都非常熟悉的一种产品,很多人在有视疲劳的时候都使用过,甚至有人会长期使用,那么我们便要了解一下珍视明滴眼液可以长期使用吗?珍视明滴眼液可以滴隐形眼镜吗?珍……机皇上手!三星GalaxyS23Ultra细节分析,打得过华三星宣布,新一代旗舰GalaxyS23系列定档2月2日发布,作为保留节目真机上手视频提前曝光,以三星的保密手段来看简直毫无意外。通过视频可以看出,机皇S23Ultra相较上一代……意料之外!匹配1。5T直喷发动机?奇瑞艾瑞泽8插电混动版实车艾瑞泽8插电混动版算是目前不少车友关注的版本之一,当然关注度最高的还是2。0TGDI版的,毕竟对于动力的渴求是不少年轻消费群体的主要诉求之一,但是新能源这种大趋势之下,插电混动……黑色紧身裤搭配黑色粗跟过膝长靴,浅灰色西服,混搭也可以很精致黑色紧身裤搭配黑色粗跟过膝长靴,浅灰色西服,混搭也可以很精致在生活中,许多女孩会注意自己的服装风格,如果他们想在冬天去购物,也应该结合自己的风格,看看这位美女的服装风格,……珍视明滴眼液红色和蓝色的区别珍视明滴眼液的危害珍视明是我们大家都很熟悉的一种眼药水,我们大家很多人都使用过,并且也都知道珍视明眼药水有红色和蓝色两种,那么珍视明滴眼液红色和蓝色的区别?珍视明滴眼液的危害?珍视明滴眼液红色和……
位居省属高校第一!最近,广东工业大学勇夺2金7银3铜,刷新记近日,第八届中国国际互联网大学生创新创业大赛总决赛圆满落下帷幕,广东工业大学共有12支项目晋级国赛、9支项目入围现场总决赛(入围项目数全省第一)。经过激烈角逐,广工最终取得2金……性能表现不输苹果,这三款国产优质手机太香了性能表现不输苹果,这三款国产优质手机太香了!红米K50Pro配置:CPU:采用天玑9000处理器,超强性能加持,兼具功耗与性能。满血版LPDDR5内存加持,配合UFS3。……美国游客拍到北京天坛照片,引起网友热议中国古人很有智慧其中大家都熟知的蓬莱阁,位于山东烟台市蓬莱区,坐落在著名的丹崖山之上,是一处始建于北宋嘉祐六年的建筑景观!该建筑历代屡加修葺,但始终没有经过重建,至今仍保持北宋原貌!蓬莱阁可以……媒体证实!C罗失去了曼联队友的支持,滕哈格希望他冬窗提前离队C罗的提前离场引发轩然大波,而曼联官方随后的一纸处罚声明再为这场风波增温。当然,支持曼联决定的占据了绝大多数。因为C罗这已经不是初犯了,季前赛对阵巴列卡诺时他就曾在比赛中场被换……安热沙防晒乳不合格!还有这些化妆品也被查今日,国家药监局通报了53批次不合规化妆品,包括染发膏、防晒乳、面膜、儿童牙膏等。其中,值得注意的是,安热沙、娜丽丝、爱和纯等知名美妆品牌也在其列,此前被广州市列入严重违法失信……山河远阔礼赞盛世赏太行山大峡谷红黄蓝绿交织交错金秋十月,人间至美。每一天都充满了惊喜,每一刻都有色彩在加深变幻,太行山大峡谷开启了一年中最为华丽的篇章。盈盈蓝天,悠悠白云,潺潺溪水,幽幽湖泊,树木也进入了一年中最为丰富的季……戴格诺特我们乐意寻求正确的出手机会SGA的成熟是他的优势直播吧11月12日讯今日NBA常规赛,雷霆132113战胜猛龙。赛后,雷霆主教练戴格诺特接受了记者采访。他讲到了球队进攻端的心态,戴格诺特表示就是大家都乐意一起努力寻求正……李少莉首次露面,她胸前证件引人注目李少莉事件在最近引发了众多网友的热烈谈论,这次谈论是她在一次发布会上穿戴奢侈,并用手指点着稿念,所以让网友们对她不满,觉得她生活奢侈,工作能力很差。在这件事情上,网上的评论铺天……油价调整消息今天11月7号,加油站调价后929598汽油售价今天是2022年11月7日,国内成品油价格调整窗口将在今晚正式开启,截至目前油价预计调整幅度为上调约0。15元左右,而具体的上调幅度还需要等待发改委公布最终的调整结果,这里提醒……中国女排5朵金花齐聚,3奥运冠军已远离赛场,段放有机会回归中国女排以8强的成绩结束了世联赛之旅,即将回国再备战世锦赛,而近日,中国女排5朵金花魏秋月、颜妮、林莉、段放、刘晏含齐聚,同游吐鲁番,引起了诸多球迷的关注。这5朵金花当中……一座中原煤城与红嘴鸥的双向奔赴平顶山市民观赏红嘴鸥。庞秋霞摄中新网平顶山12月25日电题:一座中原煤城与红嘴鸥的双向奔赴记者韩章云来啦!来啦!吃饭啦!12月25日早上八点半,庞秋霞手持鸥粮……还有没有不想奋斗的?胡润发布女富豪排行榜,进来看一看还有没有不想奋斗的?胡润发布女富豪排行榜,进来看一看。双12这天,胡润研究院发布女企业家榜。杨惠妍(碧桂园)以750亿元的总财富雄踞榜首,这也是她第十次成为中国女首富。吴亚军(……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网