对Java线程池使用的总结

    最近的项目中,遇到了一些须要频繁使用sql查询,写入文件,能够拆分子任务的状况。为了提升程序吞吐量,我使用了线程池。sql

    一开始,考虑将用户按照数量进行分片,由于在数据库查询中,oracle对where in()有不得超过1000个查询量的限制,因此考虑将每900个用户分一片,每片为一个task,交给fix线程池处理。数据库

    可是每一个task又有查询优惠券和查询待评论数两个较大的子任务,这两个子任务须要大量的sql查询,因而又考虑将这两个子任务也封装为task,交给线程池处理。但由于主任务的执行依赖子任务的结果,若是使用同一个线程池,则子任务被提交后,work队列中被执行的任务仍是主任务,cpu一直在先提交的主任务上等待Future.get()的返回,子任务得不到cpu资源去执行,一直在任务队列中等待,这将形成程序的死等待。因此将线程池由fix改成cache,但愿提交的任务能获得cpu时间,不会一直在队列中等待。后来这里也引起了问题,将在下一篇文章中说明。网络

   当用户的帐单数据被计算出来后,须要调用模板中心生成邮件,还须要将生成的邮件保存到磁盘上,这是两种不一样的io密集型任务,一个是在socket上等待,一个是在本地io上等待。考虑到若是继续提交到cache线程池,那么线程池会为每一个task生成一个线程,将耗费大量资源,cpu将频繁切换线程,下降了程序的吞吐量。所以新建一个fix线程池,将这些后续任务提交给fix线程池处理,线程池使用固定数量的work去跑,即能在不一样阻塞状况下,让程序能够继续运行,也避免了建立大量thread的资源浪费。oracle

    其实最后程序里用了五个线程池,分级使用的缘由有如下考虑:socket

    为了提升程序执行效率,能够将用户先按照语言分类,而后再按照900人一片进行分片,每片任务中,又涉及到两个频繁查询数据库的子任务,每片处理完后,又须要进行网络io生产邮件和磁盘io保存邮件。若是用相同的线程池,则上级任务生产的子任务提交fix线程池后,由于work队列还在被上级任务占用,不一样类型的io操做都将在task队列中等待,没法提升系统吞吐量。将下级任务提交到其余线程池后,下级任务就能有当即执行的机会,进行网络io和磁盘读写,提升了运行效率。线程

相关文章
相关标签/搜索