• 【Java学习笔记】ThreadPoolExecutor 翻译


    一、资源

    既然读文档是最好的,那就逼自己好好读一遍,自己学习而已....

    http://download.oracle.com/javase/1,5.0/docs/api/java/util/concurrent/ThreadPoolExecutor.html

    二、翻译

     类 ThreadPoolExecutor

           ExecutorService实现用可使用的线程来实行提交的任务,一遍用 Executors进行配置

    线程池通常用来解决两个问题:

    • 由于减小了任务执行前得开销,他们通常用来优化大量同步任务的执行
    • 在执行一系列任务的时候,他们给资源的绑定以及管理(包括那些线程)提供了一些方法

        每个ThreadPoolExecutor通常都有一些基本的统计数据,比如任务数目

         为了使线程池在程序中的多个页面都有效,此类提供了一些参数和可扩展的hooks进行调节。

    然而,建议程序员使用更方便的方法,如Executors.newCachedThreadPool()(无解线程池,可自动进行线程回收),

     Executors.newFixedThreadPool(int) (固定大小的线程池), Executors.newSingleThreadExecutor()(单任务的线程池),

    ,用这些方法来设定最常用的一些设定(the most common usage scenarios).否则,参照些列知道惊醒手动配置:

    • 核心以及最线程池的上限 

               ThreadPoolExecutor会根据corePoolSize和maxiumPoolSize设定的边界来调节池的大小。

              当新的任务通过 execute(java.lang.Runnable提交的时候,

           如果当前执行的线程数目少于corePoolSize, 则计算其他辅助线程(worker threads)是空闲的,系统还是会新开线程来处理这个请求。

            如果当前在跑的线程数多于corePoolSize小于maxiunmPoolSizem,则只有再队列满了的时候,才会开新线程。

              如果你把corePoolSize和maxiunmPoolSizem设定成相等的话,你就建立了一个固定大小的线程池。如果maximumPoolSize被设定为无限大(Integer.MAX_VALUE),则此池设定为可容纳任意多的并发线程。

        一般情况下,corePoolSize和maxiunmPoolSizem只是在构建的时候进行初始化,但是可以通过setCorePoolSize(int) setMaximumPoolSize(int)来动态更改。

    • 统一需求构造(one-demand construction)

        默认情况下,即使核心线程最初只是在新任务需要时才创建和启动的,也可以使用方法 prestartCoreThread() 或 prestartAllCoreThreads() 对其进行动态重写。

    • 创建新线程

        新线程都是在 ThreadFactory 中创建的。如果没有特别的构建,都是通过Executors.defaultThreadFactory() 来创建线程。新建的线程都在同一个 ThreadGroup 中,并且具有相同的优先级NORM_PRIORITY,并且没有守护进程的状态(non-daemon status)。提供别的ThreadFactory,你可以指定线程名,threadgroup,优先级,non-daemon status等等。如果一个ThreadFactory在newThread中返回null,线程创建失败。执行器仍然继续,但是不能再执行任何任务。

    • 保持活跃(keep-alive time)

        如果一个池中现在运行的线程数多于corePoolSize,如果多出的线程保持空闲的时间大于keepAliveTime(seegetKeepAliveTime(java.util.concurrent.TimeUnit),那么这些线程就会被关闭。这样可以在线程池不活跃的时候降低资源的消耗。如果待会线程池又活跃了,新的线程就会被建立。可通过...方法改变这个参量。将此参量设定为Long.MAX_VALUE TimeUnit.NANOSECONDS可以有效的禁止线程 from ever terminating prior to shut down。

    • 列队

        所有的BlockingQueue都被用来转移和管理已经提交的任务。使用队列来和线程池交互: 

                1、如果少于corePoolSize数目的线程正在执行,Executor会新建线程而不是用队列

                2、如果大于等于corePoolSize的线程在执行,Executor会使用队列提交消息而不是新建线程。

                3、如果请求不能放到队列中,则会建立一个新线程除非,这样做会超过maximumPoolSize,这种情况下,这个任务直接拒绝执行。

            有三个基本的队列策略:

               1、直接提交。一个好的默认选择是 SynchronousQueue ,他直接将任务交给线程而不保留。这种情况下,如果没有线程来执行此任务,则任务直接失败,所以新的线程会被建立。此策略可以避免在处理可能具有内部依赖性的请求集合时出现锁定。直接提交要求无界池以防新任务提交被拒绝。当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。

               2、无界队列。使用无界的队列(LinkedBlockingQueue),则在所有的corPoolSize量的线程繁忙时,新任务会直接加入队列中。这种情况下,maximumPoolSize完全没有用。当各个任务相互独立的时候,由于任务之间不会影响其他任务的执行,所以这样处理很好,例如,在某个web服务端。这种排队可用于处理瞬态突发请求,当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。

           3、有界队列。 有界队列( ArrayBlockingQueue)通过 maximumPoolSize的限制可有效防止资源耗尽,但是有界队列很难控制。队列大小和池的上限可能要相互折中:大队列+小池子可以降低CPU消耗,OS资源,和页面转换的预先开销,但是可能降低吞吐量(artificially low throughput)。如果任务频繁阻塞(比如I/0端口),则系统很可能会消耗比超过你预想的更多的时间(a system may be able to schedule time for more threads than you otherwise allow)。用小队列通常需要大池子,这样会使得CPU更忙但是可能遇见不可接受的开销,这些考小也会较低吞吐量。(Use of small queues generally requires larger pool sizes, which keeps CPUs busier but may encounter unacceptable scheduling overhead, which also decreases throughput.)

    • 被拒绝的任务

              当Executor被关闭或者线程数和队列容量都达到了预定义的上限时已经饱和(saturated),通过execute(java.lang.Runnable)提交的新任务会被拒绝.以上任一情况下,execute()方法会调用RejectedExecutionHandlerRejectedExecutionHandler.rejectedExecution(java.lang.Runnable, java.util.concurrent.ThreadPoolExecutor)。默认的预定义的策略如下:

               1、默认的ThreadPoolExecutor.AbortPolicy 中,hanlder在遇到拒绝时,抛出runtime异常RejectedExecutionException

               2、 ThreadPoolExecutor.CallerRunsPolicy中,调用了execute方法的线程来执行这个任务。此策略提供简单的反馈控制机制,能够减缓新任务的提交速度。(This provides a simple feedback control mechanism that will slow down the rate that new tasks are submitted.)

               3、 ThreadPoolExecutor.DiscardPolicy中,不能执行的任务直接被抛掉。

               4、 ThreadPoolExecutor.DiscardOldestPolicy中,如果excutor没有关闭,那么工作队列头部的任务将被抛弃,然后继续尝试提交。(周而复始)

             你可以自定义并且使用各种 RejectedExecutionHandler,这样做要很谨慎,特别是这个策略只在特定的容量或者只是队列策略。

    • Hook方法

             略

    • 队列维持 

            重点就是不要再程序中自己特意去操控,略。

  • 相关阅读:
    Servlet中isCommitted含义及发生的条件
    戏说java web开发中的listener和filter
    Android中以JAR形式封装控件或者类库
    华为总裁在“2012实验室干部与专家座谈会”上的发言!(转)
    C#进行Visio二次开发
    我是谁,从哪里来,将要到哪里去?
    LTE相关网元功能
    走出柏拉图的“洞穴”
    LTE的协议结构
    被联通欠款拖死,被移动集采玩死
  • 原文地址:https://www.cnblogs.com/hundan/p/2164377.html
Copyright © 2020-2023  润新知