使用tomcat线程池代替jdk线程池处理io密集型任务

/ 技术收藏 / 没有评论 / 520浏览

J.U.C线程池

JDK的J.U.C包下线程池处理比较适合处理cpu密集型任务,另外,由于线程调度逻辑上,线程提交逻辑是 core->queue->max->reject 这样的处理逻辑导致有两个缺点:

  1. max设置很多时候显得可有可无,因为只有当队列满了才会调用max创建临时worker
  2. 面对突发性高流量(未到达队列上限),固定的coreSize,线程数量的伸缩性显得有些呆板

tomcat线程池

tomcat线程池正是针对以上问题的优化,用于在高并发下,线程池具备更好的伸缩性而开发的。其中修改包括:执行拒绝策略后再尝试拯救一次线程,但最重要的改变就是重写了Queue。通过重写queue的offer方法,用来控制是否创建新的线程

    @Override
    public boolean offer(Runnable o) {
        //we can't do any checks
        if (parent==null) {
            return super.offer(o);
        }
        //we are maxed out on threads, simply queue the object
        if (parent.getPoolSize() == parent.getMaximumPoolSize()) {
            return super.offer(o);
        }
        //we have idle threads, just add it to the queue
        if (parent.getSubmittedCount()<=(parent.getPoolSize())) {
            return super.offer(o);
        }
        //if we have less threads than maximum force creation of a new thread
        if (parent.getPoolSize()<parent.getMaximumPoolSize()) {
            return false;
        }
        //if we reached here, we need to add it to the queue
        return super.offer(o);
    }

其中getSubmittedCount()获取的是已提交线程数,该值是AtomicInteger,每次提交线程时增加一,线程完成或者线程拒绝则减1。

应用

线程在操作系统中也是轻量的进程,于系统而言,也是一种昂贵的资源,不能无节制的创建,销毁,否则线程的上下文切换将会导致操作系统在用户态和内核态频繁切换,最终系统中断消耗大量cpu资源,甚至资源耗尽。开发中如果需要处理高并发的io线程,就要像tomcat线程池一样具备很高的伸缩性,那我们也可以直接自己来创建tomcat线程池,用于自己的任务,创建方法如下

//队列长度-当然设置成最大Integer是存在内存溢出风险的,根据业务调整
TaskQueue taskqueue = new TaskQueue(Integer.MAX_VALUE);
/**
 * param-1 线程名称
 * param-2 是否守护线程
 * param-3 优先级
 */
TaskThreadFactory tf = new TaskThreadFactory("my-pool-",true, Thread.NORM_PRIORITY);
ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 20, 60000, TimeUnit.MILLISECONDS,taskqueue, tf);
//这句千万不能少,否则不会调用TaskQueue的offer,原因见本文前部分源码
taskqueue.setParent(executor);