java 线程池之ThreadPoolExecutor

 最近被问如何实现一个高效的java 线程池。其实在JDK1.5 以后,并发包里面已经提供了一个同步工具类Executors。里面可以直接取一些默认实现的线程池。



Executors里面提供出来的都是静态方法,调用如下:Executors.newFixedThreadPool(1).

几种常用的线程池如下:

FixedThreadPool: 创建一个固定线程数量的线程池。

CachedThreadPool:创建一个线程可重用的线程池,大小没限制。

SingleThreadExecutor:创建只有一个线程的线程池。

ScehduledThreadPool:创建一个定时执行的线程池


从代码里面可以看到,线程池的创建其实是生成一个ThreadPoolExecutor对象来实现线程池相关功能的。

    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

看ThreadPoolExecutor类, 它最全参数的一个构造函数是:

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) 

下面说说每个参数的意义:

corePoolSize:类似于一个最小线程数。池中至少要保持这么多线程数。

maximumPoolSize:最大线程数。

keepAliveTime:就是说如果池中当前有多于 corePoolSize 的线程,则这些多出的线程在空闲时间超过 keepAliveTime 时将会终止。

unit:时间单位,给上面一个参数用的。

workQueue:所有在等待的要执行任务都会被加入到这个队列。

threadFactory:线程工厂类,给工作线程做一层包装。

handler:当 Executor 已经关闭,并且 Executor 将有限边界用于最大线程和工作队列容量,且已经饱和时,提交的新提交的任务将被拒绝。


下面看execute方法。

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        /*
         * Proceed in 3 steps:
         *
         * 1. If fewer than corePoolSize threads are running, try to
         * start a new thread with the given command as its first
         * task.  The call to addWorker atomically checks runState and
         * workerCount, and so prevents false alarms that would add
         * threads when it shouldn't, by returning false.
         *
         * 2. If a task can be successfully queued, then we still need
         * to double-check whether we should have added a thread
         * (because existing ones died since last checking) or that
         * the pool shut down since entry into this method. So we
         * recheck state and if necessary roll back the enqueuing if
         * stopped, or start a new thread if there are none.
         *
         * 3. If we cannot queue task, then we try to add a new
         * thread.  If it fails, we know we are shut down or saturated
         * and so reject the task.
         */
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {//运行的线程少于 corePoolSize,则创建新线程来处理请求
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) {//<span style="font-family: Arial, Helvetica, sans-serif;">运行的线程大于 corePoolSize,放入等待队列</span>
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))// 如果等待队列已满,则继续创建新的线程
            reject(command);
    }

执行分3步:1. 如果运行的线程少于 corePoolSize,则创建新线程来处理请求。

                      2. 如果运行的线程多于 corePoolSize 而少于 maximumPoolSize,将任务放入等待队列。然后重新当前执行器状态和线程池,如果执行状态改变,则拒绝此任务。否则新开一个线程如果pool是空的。

 3. 如果任务不能放入队列,则尝试新开一个执行线程。如果失败了,则拒绝此任务。

这里提到两个操作:addWorker和 reject 方法。

addWorker:把当前任务包装成内部类实现Worker,然后执行。Worker本身实现了Runnable接口,内部再持有一个Thread实例。Worker的run方法会循环抓取queue中的待执行任务,然后执行。而内部持有的Thread实例则用来响应线程池的中断和关闭的。

Reject是当线程池无法满足新的任务执行或关闭的时候,而采取的一个拒绝策略。

预定义的处理程序策略: 
在默认的 ThreadPoolExecutor.AbortPolicy 中,处理程序遭到拒绝将抛出运行时 RejectedExecutionException。 
在 ThreadPoolExecutor.CallerRunsPolicy 中,线程调用运行该任务的 execute 本身。此策略提供简单的反馈控制机制,能够减缓新任务的提交速度。 
在 ThreadPoolExecutor.DiscardPolicy 中,不能执行的任务将被删除。 
在 ThreadPoolExecutor.DiscardOldestPolicy 中,如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重试执行程序(如果再次失败,则重复此过程)。 
定义和使用其他种类的 RejectedExecutionHandler 类也是可能的,但这样做需要非常小心,尤其是当策略仅用于特定容量或排队策略时。

线程池关闭

    public void shutdown() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            checkShutdownAccess();
            advanceRunState(SHUTDOWN);
            interruptIdleWorkers();
            onShutdown(); // hook for ScheduledThreadPoolExecutor
        } finally {
            mainLock.unlock();
        }
        tryTerminate();
    }
未完待续。。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值