Apache Commons Pool 故事一则

转自:  http://neway6655.github.io/commons-pool,%20java/2015/12/12/ApacheCommonsPool%E6%95%85%E4%BA%8B%E4%B8%80%E5%88%99.html?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.iohtml

 

Apache Commons Pool 故事一则

最近工做中遇到一个因为对commons-pool的使用不当而引起的问题,习得正确的使用姿式后,写下这个简单的故事,帮助理解Apache Commons Pool的工做原理。java

Apache Commons Pool, Java界无人不知无人不晓的对象池技术, 经常使用于实现各类链接池, 如数据库链接池, Redis链接池等git

下面以租车公司为例子说明这张图,介绍commons pool的基本工做方式:github

Alt text

GenericObjectPool(租车公司)redis

做为租车公司,须要提供租车和收回归还的车辆的两个服务,同时它还要管理着全部的那些车辆,随着业务发展壮大,须要买新车;对于已经不能安全驾驶的车辆,须要将其销毁;同时还要按期对车辆进行安全检测等。数据库

PooledObject(租车公司的全部车辆)数组

租车公司的车辆分为三类:空闲可租用的车辆(Idle Objects),已借出的车辆(Active Objects),认为已丢弃的车辆(Anandoned Objects)安全

Borrow Object(租车)post

  • A1: 世界那么大,一位年轻人想租辆车出去逛逛
  • A2: 老板先看看有没有空闲的车
  • A3.1: 若是有,则将最近归还的车借出去,并标记为已借出(Active),若是没有空闲的车了,就买辆,同时也标记为已借出(这是一家不差钱的公司)
  • A3.2: 老板把标记好的车租给年轻人

Return Object(还车)ui

  • B1: 世界那么大,年轻人终于逛完了,回来还车
  • B2: 老板把车放回停车场,并把标记改成空闲状态(Idle),能够再被其余人租用。

TestOnBorrow/TestOnReturn(租出/归还时进行检查)

这 家公司不只不差钱,它对车辆的安全还很负责,对于租出去的车,无论是从空闲车辆里取出的,仍是新买回的,都会先检查一遍这车的好坏,总不能坑了年轻人,如 果发现有问题,立马再换一辆。归还的时候,也会检查一遍,若是有问题,就扔掉(真土豪),除此以外,公司还专门请了一位车辆安检员,按期对闲置了一段时间 的车辆进行安全检测(Evict Thread),一有问题也扔掉。

有借有还,看上去一切都很美好。

然而现实里总有意外发生:

年轻人借走车后,发现世界越逛越大,久久不肯回家。安检员按期检查时发现这车子都借出去大半年了,还没还回来,是否是丢了?因而掏出手机,”啪“的按了一下,远程将车子熄了火,标记为报废车辆(Abandoned),看成报废处理了。

Evict Thread(按期检查的安检人员)

  • C1: 对于已归还标记为空闲的车辆,安检员按期对它们抽查,若是超过一段时间没有使用,看看是否坏掉,坏了就及时做废掉(C2).
  • D1: 对于标记为已借出的对象,安检员按期检查时发现借出好久都未还,直接做废(D2)。

好了,故事讲完了,但愿你们对Commons Pool都理解了。


有兴趣的同窗能够继续往下看看咱们遇到的那个问题:

咱们使用Jedis做为redis客户端操做,在压测环境下,时不时发现Jedis报了这个异常:ClassCastException - [B cannot be cast to java.lang.Long

网上各类google百度,发现大部分网友们说是因为pipeline操做,出现异常时链接没有正确destory掉,而直接放回链接池里,被下个线程拿到后,取到链接中残留的pipeline的操做结果,从而致使类型转换错误。

这个解释听起来很在理,但反复检查代码,发现对于异常的封装都作好了,并且出现问题时也没有使用pipeline操做,应该不是网友们说的状况。

因而怀疑是否是链接池出了问题,多个线程对同一个链接作了不一样的操做,获取错了数据致使,但大名鼎鼎的commons-pool出现这样低级的错误,不可能呀?

翻了几遍commons-pool的代码后,发现多是上面说的那个按期检查的安检员捣的鬼?

对 于借出的对象,咱们配置成借出后超过10秒不归还则做废,理论上对于redis的操做,10秒确实也足够了,可是咱们对JedisPool作了进一步的封 装,在一些特殊状况下,确实会出现持有链接超过10秒的状况(这个就不展开了),致使链接还在被程序使用,读取redis的数据处理时,被清理线程无辜的 销毁了(调用jedis.quit()),

jedis的quit命令返回值就是一个Byte数组,而咱们的操做返回是Long,因而就出现了ClassCastException - [B cannot be cast to java.lang.Long这样的异常。

最后的解决办法就是将做废时间的定义适当加大。

相关文章
相关标签/搜索