java线程池

通常我们使用线程池均是使用的JDK中自带的线程池,主要有以下几种:

  • newFixedThreadPool 固定线程池
  • newSingleThreadExecutor 单线程池
  • newCachedThreadPool 无限制线程池

参数介绍

通过查看Executors源码,可以发现其实际上只是创建了一个ThreadPoolExecutor对象而已。如下代码,可以发现对于固定线程池,实际上是将nThreads设置了ThreadPoolExecutor中的corePoolSize和maximumPoolSize两个参数而已。

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 :线程池中保留的线程数量,即使空闲仍然也会保留,除非设置了allowCoreThreadTimeOut,则此时核心线程数为0
  • maximumPoolSize : 线程池中允许创建的最大线程数量,在创建的线程数达到了corePoolSize后,同时,queue中已经满员后,则会继续创建新的线程
  • keepAliveTime : 线程数量大于corePoolSize后,所能保留的最大时间,如果在该时间内没有新的任务,次线程将消亡。
  • unit : 此参数不用多说,因为有时间,必然需要时间单位
  • workQueue : 用于收留那些无法被执行的任务,其将在此处等待被提交执行
  • threadFactory : 线程创建工厂
  • handler : 用于处理那些queue有限制且达到了容量时,那些被阻塞的线程

抛弃策略

  • AbortPolicy 抛出java.util.concurrent.RejectedExecutionException异常  (默认抛弃策略)
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
    throw new RejectedExecutionException("Task " + r.toString() +
                                         " rejected from " +
                                         e.toString());
}
  • DiscardPolicy 抛弃当前的任务
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}//不对该任务做出人任何操作
  • DiscardOldestPolicy 抛弃旧的任务
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
    if (!e.isShutdown()) {
        e.getQueue().poll();//抛弃最上端的任务
        e.execute(r);//添加新的任务
    }
}
  • CallerRunsPolicy 在当前线程中执行该任务
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
    if (!e.isShutdown()) {//当前线程没有被shutdow
        r.run();//表明在当前吊起该任务的线程中直接执行
    }
}

核心方法

根据参数说明,corePoSize线程不能被回收,且会一直保留,之所以这样,是减少重复创建线程所带来的性能消耗。但是,并非对于这些线程我们无法回收,可以通过allowCoreThreadTimeOut参数来控制,默认值为false,即在线程池消亡前,保留核心线程数量,如果我们设置为ture,则可以将核心线程也一并回收,需要注意一点的是,设置参数的前提是keepAliveTime必须大于0.

public void allowCoreThreadTimeOut(boolean value) {
    if (value && keepAliveTime <= 0)
        throw new IllegalArgumentException("Core threads must have nonzero keep alive times");
    if (value != allowCoreThreadTimeOut) {
        allowCoreThreadTimeOut = value;
        if (value)
            interruptIdleWorkers();
    }
}

 

关于execute方法,获取当前的Running的线程数量,如果当前线程数量小于corePoolSize,则会直接创建一个新的work进行任务调度

public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    int c = ctl.get();
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        if (! isRunning(recheck) && remove(command))
            reject(command);
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);//创建一个新的work执行
    }
    else if (!addWorker(command, false))//判断是否已经达到了maximumPoolSize,如果没有,则继续创建新的work
        reject(command);//当前queue中已经存储容量达到上限,则执行抛弃策略
}
posted @ 2018-10-13 14:15  woniu4  阅读(197)  评论(0编辑  收藏  举报