最近的工做中,由于程序须要大量进行数据库查询,我使用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。修改完成后,从新执行程序,终于在日志中发现了新的日志,问题被解决。资源
其实到最后,我也不知道本身的分析是否彻底正确。thread