• ThreadPoolExecutor 使用说明


    一、ThreadPoolExecutor 各参数说明:

    corePoolSize 核心线程数,指定了线程池中的线程数量,它的数量决定了添加的任务是开辟新的线程去执行,还是放到workQueue任务队列中去;线程池中会维护一个最小的线程数量,即使这些线程处理空闲状态,他们也不会 被销毁,除非设置了allowCoreThreadTimeOut。这里的最小线程数量即是corePoolSize。。

    maximumPoolSize 指定了线程池中的最大线程数量,这个参数会根据你使用的workQueue任务队列的类型,决定线程池会开辟的最大线程数量;

    keepAliveTime 指的是空闲线程结束的超时时间(当一个线程不工作时,过keepAliveTime 长时间将停止该线程)。

    unit 是一个枚举,表示 keepAliveTime 的单位(有NANOSECONDS, MICROSECONDS,

    MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS,7个可选值)。

    workQueue 表示存放任务的队列(存放需要被线程池执行的线程队列)。

    threadFactory - 执行程序创建新线程时使用的工厂。

    handler - 由于超出线程范围和队列容量而使执行被阻塞时所使用的处理程序。

    拒绝策略:1、默认 直接抛出异常 AbortPolicy(中止策略)

    2CallerRunsPolicy(调用者运行策略)当触发拒绝策略时,只要线程池没有关闭,就由提交任务的当前线程处理。

    3DiscardOldestPolicy(弃老策略)功能:如果线程池未关闭,就弹出队列头部的元素,然后尝试执行

    4DiscardPolicy(丢弃策略)功能:直接静悄悄的丢弃这个任务,不触发任何动作

    BlockingQueue的选择。

    常用的几种队列

    1)ArrayBlockingQueue:规定大小的BlockingQueue,其构造必须指定大小。其所含的对象是FIFO顺序排序的。 用公平队列按FIFO顺序授予线程访问。公平通常会降低吞吐量,但降低可变性并避免饥饿。

    2)LinkedBlockingQueue:大小不固定的BlockingQueue,若其构造时指定大小,生成的BlockingQueue有大小限制,不指定大小,其大小有Integer.MAX_VALUE来决定。其所含的对象是FIFO顺序排序的。

    3)PriorityBlockingQueue:类似于LinkedBlockingQueue,但是其所含对象的排序不是FIFO,而是依据对象的自然顺序或者构造函数的Comparator决定。

    4)SynchronizedQueue:特殊的BlockingQueue,对其的操作必须是放和取交替完成。 

    队列:区分有界无界,区分是否是公平顺序执行 

    二、运行机制说明 

    1、线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。不过,就算队列里面有任务,线程池也不会马上执行它们。

    2、当调用 execute() 方法添加一个任务时,线程池会做如下判断:

        a. 如果正在运行的线程数量小于 corePoolSize,那么马上创建线程运行这个任务;

        b. 如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列。

        c. 如果这时候队列满了,而且正在运行的线程数量小于 maximumPoolSize,那么还是要创建线程运行这个任务;

        d. 如果队列满了,而且正在运行的线程数量大于或等于 maximumPoolSize,那么线程池会抛出异常,告诉调用者“我不能再接受任务了”。

    3、当一个线程完成任务时,它会从队列中取下一个任务来执行。

    4、当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运行 的线程数大于 corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它最终会收缩到 corePoolSize 的大小。

           这个过程说明,并不是先加入任务就一定会先执行。假设队列大小为 4,corePoolSize为2,maximumPoolSize为6,那么当加入15个任务时,执行的顺序类似这样:首先执行任务 1、2,然后任务3~6被放入队列。这时候队列满了,任务7、8、9、10 会被马上执行,而任务 11~15 则会抛出异常。最终顺序是:1、2、7、8、9、10、3、4、5、6。当然这个过程是针对指定大小的ArrayBlockingQueue来说,如果是LinkedBlockingQueue,因为该队列无大小限制,所以不存在上述问题。

    那么线程池的排除策略是什么样呢,一般按如下规律执行:

    A.  如果运行的线程少于 corePoolSize,则 Executor 始终首选添加新的线程,而不进行排队。

    B.  如果运行的线程等于或多于 corePoolSize,则 Executor 始终首选将请求加入队列,而不添加新的线程。

    C.  如果无法将请求加入队列,则创建新的线程,除非创建此线程超出 maximumPoolSize,在这种情况下,任务将被拒绝。 

    总结:

    1. 线程池可立即运行的最大线程数 即maximumPoolSize 参数。

    2. 线程池能包含的最大线程数 = 可立即运行的最大线程数 + 线程队列大小 (一部分立即运行,一部分装队列里等待)

    3. 核心线程数可理解为建议值,即建议使用的线程数,或者依据CPU核数

    4. add,offer,put三种添加线程到队列的方法只在队列满的时候有区别,add为抛异常,offer返回boolean值,put直到添加成功为止。

    5.同理remove,poll, take三种移除队列中线程的方法只在队列为空的时候有区别, remove为抛异常,poll为返回boolean值, take等待直到有线程可以被移除。

  • 相关阅读:
    数据库作业
    数据库知识点⑤
    数据库知识点④
    一个值得纪念的日子
    设计模式之单件模式
    HDU 5441 Travel
    HDU 5483 Nux Walpurgis
    Markdown 测试
    HDU 3271 SNIBB
    HDU 5536 Chip Factory
  • 原文地址:https://www.cnblogs.com/liyanbofly/p/15779045.html
Copyright © 2020-2023  润新知