cache线程池对数据库操作的饥饿问题

最近的工作中,因为程序需要大量进行数据库查询,我使用ArrayBlockingQueue模仿数据库连接池,里面初始化了固定数量的数据库连接对象。

我的业务中,存在主任务生成子任务,然后通过Future对象等待子任务返回结果的情况,为了避免已经在work队列的主任务一直占着cpu等待子任务返回,而子任务由于在task队列中,因此得不到cpu资源,无法执行。我使用了cache线程池,让所有任务都能被封装为thread,可以得到cpu时间。

这个设计在测试环境的小数据集下运行是正常的,任务都能执行完,但提交到生产环境,就会在运行一段时候后出问题,现象是程序日志停止,对象gc也停止,似乎程序停止或者在被阻塞住了。

后来通过jstack命令,将程序的线程调用栈帧拿来分析发现大量的线程是处于packing状态,而且他们都是在ArrayBlockingQueue的take()方法上阻塞,数量有436个。

因此怀疑,可能是有方法将A连接池中的dbHelper用完后,放到了B连接池中,导致最后A连接池中dbHelper全部泄露到了其他地方,因此没有线程能再获取到数据库连接。但对代码检查后,没有发现这种问题。

接下来再看线程栈帧,发现线程cache线程池的线程id已经到了893,证明cache线程池中有大量线程生产,这些线程都处于packing状态。只有一个线程是runnable状态,他获得了dbHelper,正在查询数据库。

于是我怀疑,是因为生成了大量线程,这些线程都需要分配cpu时间才能执行,但每个线程都只能分配到很少的cpu时间,导致持有dbHelper的线程迟迟执行不完,它无法释放dbHelper,其他线程也只能浪费着cpu时间等着。

接下来修改代码,主任务还是在cache线程池中,但其产生的子任务,放到另外一个fix线程池中执行,这样cpu就会将fix的worker队列中的查询先执行完,将dbHelper还回连接池,再去执行新的子任务,而不会创建过多的thread去等待dbHelper。修改完成后,重新执行程序,终于在日志中发现了新的日志,问题被解决。

其实到最后,我也不知道自己的分析是否完全正确。

转载于:https://my.oschina.net/u/588009/blog/789892

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值