JDK中的线程池 :工作队列和拒绝策略 上

JDK 可以创建使用Executors 创建5种类型的线程池

 Executors.newCachedThreadPool();

该方法返回一个可根据实际情况调整线程数量的线程池。线程池的线程数量不确定,但若有空闲线程可以复用,则会优先 使用可复用的线程。 若所有线程均工作,又有新的任务提交,则会创建新的线程处理任务。所有线程在当前安任务执行完毕后,将返回线程池进行复用。

  Executors.newFixedThreadPool(nThreads)

该方法创建一个固定数量的线程池。该线程池中的线程数量始终不变。当有一个新的任务提交时,线程池中若有空闲线程,则立即执行,若没有,则新的任务会被 暂存在一个任务队列中,待有空闲线程时,便处理在任务队列中的任务。

  Executors.newSingleThreadExecutor()

该方法返回一个只有一个线程的线程池。若多余一个任务被提交到该线程池,任务会被保存哎ige任务队列中,待线程空闲,按先入先出的顺序执行队列中的任务。

      Executors.newSingleThreadScheduledExecutor()

该方法返回一个ScheduledExecutorService对象,线程池大小为1。ScheduledExectorService接口在ExecutorService接口之上扩展了在给定时间执行某任务的功能, 如在固定的延时之后执行或者周期性执行某个任务。

  Executors.newScheduledThreadPool(  corePoolSize)

该方法可以返回固定数量的线程池。

具体代码实现如下:


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

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

public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

我们看下这个构造函数的源码及解释:

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

corePoolSize 指定了线程的数量。
maximumPoolSize指定了线程池的最大数量
keepAliveTime 线程池中线程的数量超过了corePoolSize 的空闲线程存活的时间。
unit keepAliveTime的单位
workQueue 任务队列
threadFactory 线程工厂
handler 拒绝策略,来不及处理任务时,采用怎样的方式拒绝任务。

下面介绍下 workQueue 和handler

参数workQueue 指被提交但未执行的任务队列,它是一个BlockingQueue接口的对象,仅用于存放Runnable对象。 根据队列功能分类,在ThreadPoolExecutor的构造函数中可使用一下几种BlockingQueue。

直接提交的队列: 该功能由 SynchronousQueue对象提供。SynchronousQueue 是一个特殊的BlocingQueue。 它没有容量,每一个插入操作都要等待一个相应的删除操作,反之,每一个删除操作都要等待对应的插入操作。如皋市使用SynchronousQueue,提交的任务不会被真实的保存,而总是将新任务提交给线程执行,如果没有空闲的进程,则尝试创建新的进程,如果进程的数量已达到最大值,则执行拒绝策略。

有界的任务队列
有界的任务队列可以使用ArrayBlockingQueue实现。当使用有界队列时,若有新的任务需要执行,如果线程池的实际线程数小于corePoolSize,则会优先创建新的线程,若大于corePoolSize,则会将新任务假如等待队列。若等待队列已满,无法加入,在总线程数,不大于maximumPoolSize的前提下,创建新的进程执行任务。若大于maximumPoolSize,则执行拒绝策略。

无界的任务队列
无界的任务队列可以通过LinkedBlockingQueue类实现。与有界队列相反,除非系统资源耗尽,否则无界的任务队列不存在任务入队失败的情况。当有新的任务到来,系统的线程数小于corePoolSize时,线程池会产生新的线程执行任务,但当系统的线程数达到corePoolSize后,就会继续增加。若后续仍有新的任务假如,而又没有空闲的线程资源,则任务直接进入对列等待。若任务创建和处理的速度差异很大,无界队列会保持快速增长,知道耗尽系统内存。

任务优先队列
优先任务队列是带有执行优先级的队列,它通过PriorityBlockingQueue实现,可以控制任务的只想你个先后顺序。它是一个特殊的无界队列。

ThreadPoolExecutor 核心执行代码如下:


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) {
            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);
        }
        else if (!addWorker(command, false))
            reject(command);
    }

这个方法会有三步:
1 如果当前线程的数量小于corePoolSize,则执行addWorker 分配线程执行任务。
2 如果当前的线程数量大于corePoolSize,则将线程放进workQueue队列中,等待执行。
如果放入失败,则将任务直接提交,分配线程进行执行。
3 如果当前线程的数量已经达到了maximumPoolSize 则执行拒绝策略。

这里写图片描述

拒绝策略(下篇继续)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值