线程相关 之 ThreadPoolExecutor源码解析【2】

先看类简介:


 An {@link ExecutorService} that executes each submitted task using
 one of possibly several pooled threads, normally configured
 using {@link Executors} factory methods.

 线程池主要解决两个问题:处理大量任务时有更好的表现;提供很多可调节的参数以及扩展钩子,上下文切换更有用。
 程序员更偏向使用:
 Executors#newCachedThreadPool;不限制大小的线程池,并自动回收线程
 Executors#newFixedThreadPool,固定大小的线程池
 Executors#newSingleThreadExecutor,单个后台线程

 <p>Thread pools address two different problems: they usually
 provide improved performance when executing large numbers of
 asynchronous tasks, due to reduced per-task invocation overhead,
 and they provide a means of bounding and managing the resources,
 including threads, consumed when executing a collection of tasks.
 Each {@code ThreadPoolExecutor} also maintains some basic
 statistics, such as the number of completed tasks.

 <p>To be useful across a wide range of contexts, this class
 provides many adjustable parameters and extensibility
 hooks. However, programmers are urged to use the more convenient
 {@link Executors} factory methods {@link
 Executors#newCachedThreadPool} (unbounded thread pool, with
 automatic thread reclamation), {@link Executors#newFixedThreadPool}
 (fixed size thread pool) and {@link
 Executors#newSingleThreadExecutor} (single background thread), that
 preconfigure settings for the most common usage
 scenarios. Otherwise, use the following guide when manually
 configuring and tuning this class:

 <dl>

 <dt>Core and maximum pool sizes</dt>

 ThreadPoolExecutor 会自动调整线程池大小 getPoolSize(),通过 corePoolSize getCorePoolSize() 和 maximumPoolSize getMaximumPoolSize();
 当新任务通过 execute()提交时,并且运行的线程数量少于 corePoolSize,即使其他的线程是空闲的,也会创建一个新的线程来处理这个请求。如果运行的线程数量,大于 corePoolSize,
 小于 maximumPoolSize,仅当队列满的时候,一个新得线程才会被创建(当队列不满的时候,会首先放入队列中)。
 如果设置的 corePoolSize 等于 maximumPoolSize,会创建一个固定大小的线程池。
 如果设置的 maximumPoolSize 无限大,比如等于 Integer.MAX_VALUE,允许无限多的任务并发处理。
 典型的做法是,通过构造方法来设置 corePoolSize和 maximumPoolSize,但也可以通过 setCorePoolSize 和 setMaximumPoolSize 来动态设置。

 <dd>A {@code ThreadPoolExecutor} will automatically adjust the
 pool size (see {@link #getPoolSize})
 according to the bounds set by
 corePoolSize (see {@link #getCorePoolSize}) and
 maximumPoolSize (see {@link #getMaximumPoolSize}).

 When a new task is submitted in method {@link #execute(Runnable)},
 and fewer than corePoolSize threads are running, a new thread is
 created to handle the request, even if other worker threads are
 idle.  If there are more than corePoolSize but less than
 maximumPoolSize threads running, a new thread will be created only
 if the queue is full.  By setting corePoolSize and maximumPoolSize
 the same, you create a fixed-size thread pool. By setting
 maximumPoolSize to an essentially unbounded value such as {@code
 Integer.MAX_VALUE}, you allow the pool to accommodate an arbitrary
 number of concurrent tasks. Most typically, core and maximum pool
 sizes are set only upon construction, but they may also be changed
 dynamically using {@link #setCorePoolSize} and {@link
 #setMaximumPoolSize}. </dd>

 <dt>On-demand construction</dt>

 按需构造
 一般来说,只有任务到达的时候,核心线程才会被初始化创建,但是这可以通过 prestartCoreThread或者 prestartAllCoreThreads来动态重写。
 当使用一个非空队列来创建的时候,可能想要预热一些线程
 
 <dd>By default, even core threads are initially created and
 started only when new tasks arrive, but this can be overridden
 dynamically using method {@link #prestartCoreThread} or {@link
 #prestartAllCoreThreads}.  You probably want to prestart threads if
 you construct the pool with a non-empty queue. </dd>

 <dt>Creating new threads</dt>

 通过 ThreadFactory创建一个新的线程.如果不是特殊情况,通过 Executors#defaultThreadFactory创建的线程,都是在同一个线程组中,拥有相同的优先级和非守护状态。
 通过提供一个不同的 ThreadFactory,可以修改线程名称、线程组、优先级、守护状态等等。。
 如果 ThreadFactory通过 newThread() 创建线程时返回了null,不能再执行任何的任务。
 线程应该有 modifyThread(运行时权限),如果使用线程池的工作线程或其他线程没有这个权限,服务可能会被降级:配置不会被即时生效
 
 <dd>New threads are created using a {@link ThreadFactory}.  If not
 otherwise specified, a {@link Executors#defaultThreadFactory} is
 used, that creates threads to all be in the same {@link
 ThreadGroup} and with the same {@code NORM_PRIORITY} priority and
 non-daemon status. By supplying a different ThreadFactory, you can
 alter the thread's name, thread group, priority, daemon status,
 etc. If a {@code ThreadFactory} fails to create a thread when asked
 by returning null from {@code newThread}, the executor will
 continue, but might not be able to execute any tasks. Threads
 should possess the "modifyThread" {@code RuntimePermission}. If
 worker threads or other threads using the pool do not possess this
 permission, service may be degraded: configuration changes may not
 take effect in a timely manner, and a shutdown pool may remain in a
 state in which termination is possible but not completed.</dd>

 <dt>Keep-alive times</dt>

 池中当前线程的数量大于 corePoolSize,过多的空闲线程在超时(getKeepAliveTime)后会被中断。当线程池不活跃的时候,可以减少资源浪费。
 之后当线程池再次活跃时,新的线程会被创建。这个参数也可以通过(setKeepAliveTime)来动态的改变。将值设置为 Integer.MAX_VALUE 可以阻止线程在终止之前被关闭。
 一般来说,keep-alive 策略只是在数量多于 corePoolSize 时生效。但是方法(allowCoreThreadTimeOut)也可以在核心线程上应用这个策略,只要 keepAliveTime 非0.
 
 <dd>If the pool currently has more than corePoolSize threads,
 excess threads will be terminated if they have been idle for more
 than the keepAliveTime (see {@link #getKeepAliveTime(TimeUnit)}).
 This provides a means of reducing resource consumption when the
 pool is not being actively used. If the pool becomes more active
 later, new threads will be constructed. This parameter can also be
 changed dynamically using method {@link #setKeepAliveTime(long,
 TimeUnit)}.  Using a value of {@code Long.MAX_VALUE} {@link
 TimeUnit#NANOSECONDS} effectively disables idle threads from ever
 terminating prior to shut down. By default, the keep-alive policy
 applies only when there are more than corePoolSize threads. But
 method {@link #allowCoreThreadTimeOut(boolean)} can be used to
 apply this time-out policy to core threads as well, so long as the
 keepAliveTime value is non-zero. </dd>

 <dt>Queuing</dt>

 任何的 BlockingQueue 都可能被用来转移和持有提交的任务.队列的使用和池的大小相互影响:
 1.如果少于corePoolSize数量的线程在运行,Executes总是增加新的进程,而不放入队列
 2.如果大于等于corePoolSize数量的线程在运行,Executes总是入队而不创建新的线程
 3.当一个请求不能入队时,除非超过了 maximumPoolSize,会创建新的线程,否则,任务会被拒绝。
 
 
 <dd>Any {@link BlockingQueue} may be used to transfer and hold
 submitted tasks.  The use of this queue interacts with pool sizing:

 <ul>

 <li> If fewer than corePoolSize threads are running, the Executor
 always prefers adding a new thread
 rather than queuing.</li>

 <li> If corePoolSize or more threads are running, the Executor
 always prefers queuing a request rather than adding a new
 thread.</li>

 <li> If a request cannot be queued, a new thread is created unless
 this would exceed maximumPoolSize, in which case, the task will be
 rejected.</li>

 </ul>

 There are three general strategies for queuing:
 <ol>
 一般来说,对于入队有3个策略:
 1、直接传送.对于直接传送任务而不持有任务来说,SynchronousQueue是一个好的默认选择。如果没有可用的线程,尝试入队的任务就会失败,因此一个新的线程会被创建。
 直接传送需要不限制大小的 maximumPoolSize,避免新提交的任务失败。
 2、无界队列,使用无界队列如(LinkedBlockingQueue),当所有的线程(corePoolSize)都在忙的时候,会导致新的任务等待。
 因此,不超过corePoolSize数量的线程都会被创建(maximumPoolSize不再起任何作用)。当任务相互独立时,可能比较合适,因此任务不能影响其他任务的执行;
 3、有界队列。一个有界队列(ArrayBlockingQueue),有限的 maximumPoolSize 有助于预防资源枯竭。但是也更难协调和控制。
 队列大小和池的大小相互影响:使用一个大的队列和小的池可以最小化cpu使用、系统资源、上下文切换,但是也会导致人为的低吞吐量。
 如果任务频繁阻塞(例如I/O限制),系统调度的线程数量可能比你允许的还要大。使用一个小的队列,通常需要更大的线程池,这会充分利用cpu但会碰到不可接受的调度开销,
 这也会降低吞吐量
 
 <li> <em> Direct handoffs.</em> A good default choice for a work
 queue is a {@link SynchronousQueue} that hands off tasks to threads
 without otherwise holding them. Here, an attempt to queue a task
 will fail if no threads are immediately available to run it, so a
 new thread will be constructed. This policy avoids lockups when
 handling sets of requests that might have internal dependencies.
 Direct handoffs generally require unbounded maximumPoolSizes to
 avoid rejection of new submitted tasks. This in turn admits the
 possibility of unbounded thread growth when commands continue to
 arrive on average faster than they can be processed.  </li>

 <li><em> Unbounded queues.</em> Using an unbounded queue (for
 example a {@link LinkedBlockingQueue} without a predefined
 capacity) will cause new tasks to wait in the queue when all
 corePoolSize threads are busy. Thus, no more than corePoolSize
 threads will ever be created. (And the value of the maximumPoolSize
 therefore doesn't have any effect.)  This may be appropriate when
 each task is completely independent of others, so tasks cannot
 affect each others execution; for example, in a web page server.
 While this style of queuing can be useful in smoothing out
 transient bursts of requests, it admits the possibility of
 unbounded work queue growth when commands continue to arrive on
 average faster than they can be processed.  </li>

 <li><em>Bounded queues.</em> A bounded queue (for example, an
 {@link ArrayBlockingQueue}) helps prevent resource exhaustion when
 used with finite maximumPoolSizes, but can be more difficult to
 tune and control.  Queue sizes and maximum pool sizes may be traded
 off for each other: Using large queues and small pools minimizes
 CPU usage, OS resources, and context-switching overhead, but can
 lead to artificially low throughput.  If tasks frequently block (for
 example if they are I/O bound), a system may be able to schedule
 time for more threads than you otherwise allow. Use of small queues
 generally requires larger pool sizes, which keeps CPUs busier but
 may encounter unacceptable scheduling overhead, which also
 decreases throughput.  </li>

 </ol>

 </dd>

 <dt>Rejected tasks</dt>
 
 当 Executes 被关闭的时候,以及池的 maximum和工作队列容量都已经饱和的时候,通过(execute)提交新的任务会被拒绝。
 在这种情况下,execute方法会 invoke 调用 RejectedExecutionHandler#rejectedExecution()方法,提供有4中处理策略:
 1、默认 ThreadPoolExecutor.AbortPolicy ,拒绝的时候,处理器抛出来一个运行时异常(RejectedExecutionException)
 2、ThreadPoolExecutor.CallerRunsPolicy,线程调用execute自身来运行这个任务。这提供了一个简单的回调控制机制,来减慢新任务提交的频率。
 3、ThreadPoolExecutor.DiscardPolicy,任务会被简单的丢弃。
 4、ThreadPoolExecutor.DiscardOldestPolicy,如果 execute没有关闭,任务队列前头的任务会被丢弃,然后 execution会重试(可能会再次失败)
 定义使用其他类型的 RejectedExecutionHandler 类时可能的。这样做需要当心,特别是当策略被设计并工作在特定容量或者队列策略下。
 
 <dd>New tasks submitted in method {@link #execute(Runnable)} will be
 <em>rejected</em> when the Executor has been shut down, and also when
 the Executor uses finite bounds for both maximum threads and work queue
 capacity, and is saturated.  In either case, the {@code execute} method
 invokes the {@link
 RejectedExecutionHandler#rejectedExecution(Runnable, ThreadPoolExecutor)}
 method of its {@link RejectedExecutionHandler}.  Four predefined handler
 policies are provided:

 <ol>

 <li> In the default {@link ThreadPoolExecutor.AbortPolicy}, the
 handler throws a runtime {@link RejectedExecutionException} upon
 rejection. </li>

 <li> In {@link ThreadPoolExecutor.CallerRunsPolicy}, the thread
 that invokes {@code execute} itself runs the task. This provides a
 simple feedback control mechanism that will slow down the rate that
 new tasks are submitted. </li>

 <li> In {@link ThreadPoolExecutor.DiscardPolicy}, a task that
 cannot be executed is simply dropped.  </li>

 <li>In {@link ThreadPoolExecutor.DiscardOldestPolicy}, if the
 executor is not shut down, the task at the head of the work queue
 is dropped, and then execution is retried (which can fa
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值