模块 java.base

类 ForkJoinPool

所有已实现的接口:
AutoCloseable , Executor , ExecutorService

public class ForkJoinPool extends AbstractExecutorService
用于运行 ForkJoinTask ExecutorService ForkJoinPool 为来自非ForkJoinTask 客户端的提交以及管理和监控操作提供入口点。

ForkJoinPool 与其他类型的 ExecutorService 的不同之处主要在于采用 work-stealing :池中的所有线程都试图查找并执行提交给池和/或由其他活动任务创建的任务(如果不存在,最终会阻塞等待工作)。当大多数任务产生其他子任务时(大多数 ForkJoinTask s 也是如此),以及当许多小任务从外部客户端提交到池时,这可以实现高效处理。特别是在构造函数中将 asyncMode 设置为 true 时, ForkJoinPool s 也可能适用于从未加入的事件式任务。所有工作线程都使用 Thread.isDaemon() set true 进行初始化。

静态 commonPool() 适用于大多数应用程序。公共池由未明确提交到指定池的任何 ForkJoinTask 使用。使用公共池通常会减少资源使用(其线程在不使用期间会慢慢回收,并在后续使用时恢复)。

对于需要单独或自定义池的应用程序, ForkJoinPool 可以用给定的目标并行级别构建;默认情况下,等于可用处理器的数量。池尝试通过动态添加、暂停或恢复内部工作线程来维持足够的活动(或可用)线程,即使某些任务因等待加入其他任务而停止。但是,面对阻塞的 I/O 或其他非托管同步,无法保证进行此类调整。嵌套的 ForkJoinPool.ManagedBlocker 接口可以扩展所容纳的同步类型。可以使用具有对应于类 ThreadPoolExecutor 中记录的参数的构造函数来覆盖默认策略。

除了执行和生命周期控制方法之外,此类还提供状态检查方法(例如 getStealCount() ),旨在帮助开发、调整和监视 fork/join 应用程序。此外,方法 toString() 以方便的形式返回池状态的指示,以便进行非正式监视。

与其他ExecutorServices一样,下表总结了三种主要的任务执行方式。这些设计主要供尚未参与当前池中的 fork/join 计算的客户端使用。这些方法的主要形式接受 ForkJoinTask 的实例,但重载形式也允许混合执行基于普通 RunnableCallable 的活动。然而,已经在池中执行的任务通常应该使用表中列出的内部计算形式,除非使用通常不连接的异步事件式任务,在这种情况下,方法选择之间几乎没有区别。

任务执行方式总结
来自非分叉/加入客户的呼叫 从 fork/join 计算中调用
安排异步执行 execute(ForkJoinTask) ForkJoinTask.fork()
等待并获得结果 invoke(ForkJoinTask) ForkJoinTask.invoke()
安排exec并获得Future submit(ForkJoinTask) ForkJoinTask.fork() (ForkJoinTasks are 期货)

用于构造公共池的参数可以通过设置以下 系统属性 来控制:

如果没有通过系统属性提供线程工厂,那么公共池将使用一个使用系统类加载器作为 线程上下文类加载器 的工厂。此外,如果存在 SecurityManager ,则公共池使用工厂提供未启用 Permissions 的线程,并且不保证跨任务保留 ThreadLocal 变量的值。在建立这些设置时出现任何错误时,将使用默认参数。通过将 parallelism 属性设置为零和/或使用可能返回 null 的工厂,可以禁用或限制公共池中线程的使用。然而,这样做可能会导致未加入的任务永远不会被执行。
实现注意事项:
此实现将运行线程的最大数量限制为 32767。尝试创建大于最大数量的池会导致 IllegalArgumentException。此外,此实现仅在池关闭或内部资源耗尽时才拒绝提交的任务(即通过抛出 RejectedExecutionException )。
自从:
1.7
  • 字段详细信息

    • defaultForkJoinWorkerThreadFactory

      public static final ForkJoinPool.ForkJoinWorkerThreadFactory  defaultForkJoinWorkerThreadFactory
      创建一个新的 ForkJoinWorkerThread。除非在 ForkJoinPool 构造方法中被重写,否则将使用此工厂。
  • 构造方法详细信息

    • ForkJoinPool

      public ForkJoinPool()
      抛出:
      SecurityException - 如果存在安全管理器并且不允许调用者修改线程,因为它不包含 RuntimePermission ("modifyThread")
    • ForkJoinPool

      public ForkJoinPool(int parallelism)
      使用所有其他参数的默认值创建具有指定并行级别的 ForkJoinPool(请参阅 ForkJoinPool(int, ForkJoinWorkerThreadFactory, UncaughtExceptionHandler, boolean, int, int, int, Predicate, long, TimeUnit) )。
      参数:
      parallelism - 并行度
      抛出:
      IllegalArgumentException - 如果并行度小于或等于零,或大于实现限制
      SecurityException - 如果存在安全管理器并且不允许调用者修改线程,因为它不包含 RuntimePermission ("modifyThread")
    • ForkJoinPool

      public ForkJoinPool(int parallelism, ForkJoinPool.ForkJoinWorkerThreadFactory  factory, Thread.UncaughtExceptionHandler  handler, boolean asyncMode)
      使用给定的参数创建一个 ForkJoinPool(对其他参数使用默认值——参见 ForkJoinPool(int, ForkJoinWorkerThreadFactory, UncaughtExceptionHandler, boolean, int, int, int, Predicate, long, TimeUnit) )。
      参数:
      parallelism - 并行度。对于默认值,请使用 Runtime.availableProcessors()
      factory - 创建新线程的工厂。对于默认值,请使用 defaultForkJoinWorkerThreadFactory
      handler - 由于执行任务时遇到不可恢复的错误而终止的内部工作线程的处理程序。对于默认值,请使用 null
      asyncMode - 如果为真,则为从未加入的分叉任务建立本地先进先出调度模式。在工作线程仅处理事件式异步任务的应用程序中,此模式可能比默认的基于本地堆栈的模式更合适。对于默认值,请使用 false
      抛出:
      IllegalArgumentException - 如果并行度小于或等于零,或大于实现限制
      NullPointerException - 如果工厂为空
      SecurityException - 如果存在安全管理器并且不允许调用者修改线程,因为它不包含 RuntimePermission ("modifyThread")
    • ForkJoinPool

      public ForkJoinPool(int parallelism, ForkJoinPool.ForkJoinWorkerThreadFactory  factory, Thread.UncaughtExceptionHandler  handler, boolean asyncMode, int corePoolSize, int maximumPoolSize, int minimumRunnable, Predicate <? super ForkJoinPool > saturate, long keepAliveTime, TimeUnit  unit)
      使用给定的参数创建一个 ForkJoinPool
      参数:
      parallelism - 并行度。对于默认值,请使用 Runtime.availableProcessors()
      factory - 创建新线程的工厂。对于默认值,请使用 defaultForkJoinWorkerThreadFactory
      handler - 由于执行任务时遇到不可恢复的错误而终止的内部工作线程的处理程序。对于默认值,请使用 null
      asyncMode - 如果为真,则为从未加入的分叉任务建立本地先进先出调度模式。在工作线程仅处理事件式异步任务的应用程序中,此模式可能比默认的基于本地堆栈的模式更合适。对于默认值,请使用 false
      corePoolSize - 要保留在池中的线程数(除非在经过的保持活动后超时)。通常(默认情况下)这是与并行度级别相同的值,但如果任务经常阻塞,可以将其设置为更大的值以减少动态开销。使用较小的值(例如 0 )与默认值具有相同的效果。
      maximumPoolSize - 允许的最大线程数。当达到最大值时,替换阻塞线程的尝试将失败。 (但是,由于不同线程的创建和终止可能会重叠,并且可能由给定的线程工厂管理,因此可能会暂时超过此值。)要安排与公共池默认使用的值相同的值,请使用 256 加上parallelism 水平。 (默认情况下,公共池允许最多 256 个备用线程。)使用大于实现的总线程限制的值(例如 Integer.MAX_VALUE )与使用此限制(默认值)具有相同的效果。
      minimumRunnable - 未被连接或 ForkJoinPool.ManagedBlocker 阻塞的最小允许核心线程数。为了保证进度,当未阻塞的线程太少,可能存在未执行的任务时,构造新的线程,直到给定的maximumPoolSize。对于默认值,使用 1 以确保活性。较大的值可能会在存在受阻活动的情况下提高吞吐量,但也可能不会,因为会增加开销。当提交的任务不能具有需要额外线程的依赖项时,零值可能是可以接受的。
      saturate - 如果非空,则在尝试创建超过最大允许线程总数时调用谓词。默认情况下,当一个线程将要在连接或 ForkJoinPool.ManagedBlocker 上阻塞,但由于会超过 maximumPoolSize 而无法被替换时,将抛出 RejectedExecutionException 。但是,如果此谓词返回 true ,则不会抛出任何异常,因此池会继续以少于可运行线程的目标数量运行,这可能无法确保进度。
      keepAliveTime - 自上次使用线程终止之前经过的时间(然后在需要时替换)。对于默认值,请使用 60, TimeUnit.SECONDS
      unit - keepAliveTime 参数的时间单位
      抛出:
      IllegalArgumentException - 如果并行度小于或等于零,或者大于实现限制,或者如果 maximumPoolSize 小于并行度,或者如果 keepAliveTime 小于或等于零。
      NullPointerException - 如果工厂为空
      SecurityException - 如果存在安全管理器并且不允许调用者修改线程,因为它不包含 RuntimePermission ("modifyThread")
      自从:
      9
  • 方法详情

    • commonPool

      public static ForkJoinPool  commonPool()
      返回公共池实例。这个池是静态构建的;它的运行状态不受 shutdown() shutdownNow() 尝试的影响。然而,这个池和任何正在进行的处理都会在程序 System.exit(int) 时自动终止。任何依赖异步任务处理在程序终止前完成的程序都应在退出前调用 commonPool(). awaitQuiescence
      返回:
      公共池实例
      自从:
      1.8
    • invoke

      public <T> T invoke(ForkJoinTask <T> task)
      执行给定的任务,完成后返回结果。如果计算遇到未经检查的异常或错误,它将作为此调用的结果重新抛出。重新抛出的异常与常规异常的行为方式相同,但在可能的情况下,包含当前线程和实际遇到异常的线程的堆栈跟踪(例如使用 ex.printStackTrace() 显示);至少只有后者。
      类型参数:
      T - 任务结果的类型
      参数:
      task - 任务
      返回:
      任务的结果
      抛出:
      NullPointerException - 如果任务为空
      RejectedExecutionException - 如果无法安排任务执行
    • execute

      public void execute(ForkJoinTask <?> task)
      安排给定任务的(异步)执行。
      参数:
      task - 任务
      抛出:
      NullPointerException - 如果任务为空
      RejectedExecutionException - 如果无法安排任务执行
    • execute

      public void execute(Runnable  task)
      从接口 Executor 复制的描述
      在将来的某个时间执行给定的命令。该命令可以在新线程、池线程或调用线程中执行,由 Executor 实现自行决定。
      参数:
      task - 可运行任务
      抛出:
      NullPointerException - 如果任务为空
      RejectedExecutionException - 如果无法安排任务执行
    • submit

      public <T> ForkJoinTask <T> submit(ForkJoinTask <T> task)
      提交 ForkJoinTask 以供执行。
      实现要求:
      从不在此池中的线程调用时,此方法等效于 externalSubmit(ForkJoinTask)
      类型参数:
      T - 任务结果的类型
      参数:
      task - 要提交的任务
      返回:
      任务
      抛出:
      NullPointerException - 如果任务为空
      RejectedExecutionException - 如果无法安排任务执行
    • submit

      public <T> ForkJoinTask <T> submit(Callable <T> task)
      从接口 ExecutorService 复制的描述
      提交一个有返回值的任务以供执行,并返回一个代表任务未决结果的 Future。 Future 的 get 方法将在成功完成后返回任务结果。

      如果你想立即阻塞等待任务,你可以使用 result = exec.submit(aCallable).get(); 形式的结构

      注意:Executors 类包含一组方法,可以将一些其他常见的类似闭包的对象(例如,PrivilegedAction 转换为 Callable 形式)以便提交。

      指定者:
      submit 在接口 ExecutorService
      重写:
      submit 在类 AbstractExecutorService
      类型参数:
      T - 任务结果的类型
      参数:
      task - 要提交的任务
      返回:
      代表任务未决完成的 Future
      抛出:
      NullPointerException - 如果任务为空
      RejectedExecutionException - 如果无法安排任务执行
    • submit

      public <T> ForkJoinTask <T> submit(Runnable  task, T result)
      从接口 ExecutorService 复制的描述
      提交一个 Runnable 任务以供执行并返回一个代表该任务的 Future。 Future 的 get 方法将在成功完成后返回给定的结果。
      指定者:
      submit 在接口 ExecutorService
      重写:
      submit 在类 AbstractExecutorService
      类型参数:
      T - 结果的类型
      参数:
      task - 要提交的任务
      result - 要返回的结果
      返回:
      代表任务未决完成的 Future
      抛出:
      NullPointerException - 如果任务为空
      RejectedExecutionException - 如果无法安排任务执行
    • submit

      public ForkJoinTask <?> submit(Runnable  task)
      从接口 ExecutorService 复制的描述
      提交一个 Runnable 任务以供执行并返回一个代表该任务的 Future。 Future 的 get 方法将在 successful 完成后返回 null
      指定者:
      submit 在接口 ExecutorService
      重写:
      submit 在类 AbstractExecutorService
      参数:
      task - 要提交的任务
      返回:
      代表任务未决完成的 Future
      抛出:
      NullPointerException - 如果任务为空
      RejectedExecutionException - 如果无法安排任务执行
    • externalSubmit

      public <T> ForkJoinTask <T> externalSubmit(ForkJoinTask <T> task)
      提交给定的任务,就像从非 ForkJoinTask 客户端提交一样。即使从池中的线程调用,任务也会添加到调度队列以提交到池。
      实现要求:
      从不在此池中的线程调用时,此方法等效于 submit(ForkJoinTask)
      类型参数:
      T - 任务结果的类型
      参数:
      task - 要提交的任务
      返回:
      任务
      抛出:
      NullPointerException - 如果任务为空
      RejectedExecutionException - 如果无法安排任务执行
      自从:
      20
    • lazySubmit

      public <T> ForkJoinTask <T> lazySubmit(ForkJoinTask <T> task)
      提交给定的任务,但不保证它最终会在没有可用活动线程的情况下执行。在某些上下文中,此方法可以减少争用和开销,方法依赖于现有线程(如果在此池中运行,则可能包括调用线程)最终可用于执行任务的上下文特定知识。
      类型参数:
      T - 任务结果的类型
      参数:
      task - 任务
      返回:
      任务
      抛出:
      NullPointerException - 如果任务为空
      RejectedExecutionException - 如果无法安排任务执行
      自从:
      19
    • setParallelism

      public int setParallelism(int size)
      更改此池的目标并行度,控制工作线程的未来创建、使用和终止。应用程序包括可用处理器数量随时间变化的上下文。
      实现注意事项:
      此实现将最大运行线程数限制为 32767
      参数:
      size - 目标并行度
      返回:
      先前的并行度级别。
      抛出:
      IllegalArgumentException - 如果大小小于 1 或大于此池支持的最大值。
      UnsupportedOperationException - 这是commonPool() ,并行度级别由系统属性 java.util.concurrent.ForkJoinPool.common.parallelism 设置。
      SecurityException - 如果存在安全管理器并且不允许调用者修改线程,因为它不包含 RuntimePermission ("modifyThread")
      自从:
      19
    • invokeAll

      public <T> List <Future <T>> invokeAll(Collection <? extends Callable <T>> tasks)
      从接口 ExecutorService 复制的描述
      执行给定的任务,在所有任务完成时返回一个 Futures 列表,其中包含它们的状态和结果。 Future.isDone() 是返回列表中每个元素的 true。请注意,completed 任务可以正常终止或通过抛出异常终止。如果在执行此操作时修改了给定的集合,则此方法的结果是未定义的。
      类型参数:
      T - 从任务返回的值的类型
      参数:
      tasks - 任务集合
      返回:
      代表任务的 Futures 列表,顺序与迭代器为给定任务列表生成的顺序相同,每个任务都已完成
      抛出:
      NullPointerException - 如果任务或其任何元素是 null
      RejectedExecutionException - 如果无法安排任何任务执行
    • getFactory

      返回用于构建新工人的工厂。
      返回:
      用于建造新工人的工厂
    • getUncaughtExceptionHandler

      public Thread.UncaughtExceptionHandler  getUncaughtExceptionHandler()
      返回由于执行任务时遇到不可恢复的错误而终止的内部工作线程的处理程序。
      返回:
      处理程序,如果没有则为 null
    • getParallelism

      public int getParallelism()
      返回此池的目标并行度级别。
      返回:
      该池的目标并行度级别
    • getCommonPoolParallelism

      public static int getCommonPoolParallelism()
      返回公共池的目标并行度级别。
      返回:
      公共池的目标并行度级别
      自从:
      1.8
    • getPoolSize

      public int getPoolSize()
      返回已启动但尚未终止的工作线程数。此方法返回的结果可能与 getParallelism() 不同,当线程被创建以在其他线程被协作阻塞时保持并行性。
      返回:
      工作线程数
    • getAsyncMode

      public boolean getAsyncMode()
      如果此池对从未加入的分叉任务使用本地先进先出调度模式,则返回 true
      返回:
      true 如果这个池使用异步模式
    • getRunningThreadCount

      public int getRunningThreadCount()
      返回未阻塞等待加入任务或其他托管同步的工作线程数的估计值。此方法可能会高估正在运行的线程数。
      返回:
      工作线程数
    • getActiveThreadCount

      public int getActiveThreadCount()
      返回当前正在窃取或执行任务的线程数的估计值。此方法可能会高估活动线程的数量。
      返回:
      活动线程数
    • isQuiescent

      public boolean isQuiescent()
      如果所有工作线程当前都空闲,则返回 true。空闲工作人员是无法获得要执行的任务的工作人员,因为没有任务可以从其他线程窃取,并且没有待处理的提交到池中。这种方法是保守的;它可能不会在所有线程空闲时立即返回 true,但如果线程保持不活动状态,它最终会变为真。
      返回:
      true 如果所有线程当前都空闲
    • getStealCount

      public long getStealCount()
      返回由提交者以外的线程执行的已完成任务总数的估计值。当池不静止时,报告的值低估了实际的窃取总数。这个值可能对监视和调整 fork/join 程序很有用:一般来说,窃取计数应该足够高以保持线程忙碌,但也应该足够低以避免线程间的开销和争用。
      返回:
      抢断次数
    • getQueuedTaskCount

      public long getQueuedTaskCount()
      返回当前由工作线程保留在队列中的任务总数的估计值(但不包括提交到池中但尚未开始执行的任务)。该值只是一个近似值,是通过遍历池中的所有线程获得的。此方法可能对调整任务粒度很有用。
      返回:
      排队任务的数量
      参见:
    • getQueuedSubmissionCount

      public int getQueuedSubmissionCount()
      返回提交给该池但尚未开始执行的任务数量的估计值。此方法所花费的时间可能与提交的数量成正比。
      返回:
      排队提交的数量
    • hasQueuedSubmissions

      public boolean hasQueuedSubmissions()
      如果有任何提交到该池但尚未开始执行的任务,则返回 true
      返回:
      true 如果有任何排队的提交
    • pollSubmission

      protected ForkJoinTask <?> pollSubmission()
      删除并返回下一个未执行的提交(如果有)。此方法在此类的扩展中可能很有用,可以在具有多个池的系统中重新分配工作。
      返回:
      下一次提交,或者 null 如果没有
    • drainTasksTo

      protected int drainTasksTo(Collection <? super ForkJoinTask <?>> c)
      从调度队列中删除所有可用的未执行的已提交和分叉的任务,并将它们添加到给定的集合中,而不改变它们的执行状态。这些可能包括人工生成或包装的任务。此方法旨在仅在已知池处于静止状态时调用。其他时间的调用可能不会删除所有任务。尝试将元素添加到集合 c 时遇到的失败可能会导致在抛出相关异常时元素不在任何一个或两个集合中。如果在操作进行时修改了指定的集合,则此操作的行为是未定义的。
      参数:
      c - 将元素转移到的集合
      返回:
      转移的元素数量
    • toString

      public String  toString()
      返回标识此池及其状态的字符串,包括运行状态、并行级别以及工作程序和任务计数的指示。
      重写:
      toString 在类 Object
      返回:
      标识此池及其状态的字符串
    • shutdown

      public void shutdown()
      可能启动有序关闭,其中执行先前提交的任务,但不会接受新任务。如果这是 commonPool() ,调用对执行状态没有影响,如果已经关闭则没有额外影响。在此方法过程中正在同时提交的任务可能会也可能不会被拒绝。
      抛出:
      SecurityException - 如果存在安全管理器并且不允许调用者修改线程,因为它不包含 RuntimePermission ("modifyThread")
    • shutdownNow

      public List <Runnable > shutdownNow()
      可能会尝试取消和/或停止所有任务,并拒绝所有随后提交的任务。如果这是 commonPool() ,调用对执行状态没有影响,如果已经关闭则没有额外影响。否则,在此方法过程中正在提交或并发执行的任务可能会被拒绝,也可能不会被拒绝。此方法取消现有和未执行的任务,以允许在存在任务依赖性的情况下终止。所以该方法总是返回一个空列表(与其他一些执行器的情况不同)。
      返回:
      一个空列表
      抛出:
      SecurityException - 如果存在安全管理器并且不允许调用者修改线程,因为它不包含 RuntimePermission ("modifyThread")
    • isTerminated

      public boolean isTerminated()
      如果关闭后所有任务都已完成,则返回 true
      返回:
      true 如果关闭后所有任务都已完成
    • isTerminating

      public boolean isTerminating()
      如果终止过程已经开始但尚未完成,则返回 true。此方法可能对调试有用。返回 true 报告关闭后有足够的时间可能表示提交的任务已忽略或抑制中断,或者正在等待 I/O,导致此执行程序无法正确终止。 (请参阅类 ForkJoinTask 的咨询说明,指出任务通常不应包含阻塞操作。但如果它们包含,则它们必须在中断时中止它们。)
      返回:
      true 如果终止但尚未终止
    • isShutdown

      public boolean isShutdown()
      如果此池已关闭,则返回 true
      返回:
      true 如果这个池已经关闭
    • awaitTermination

      public boolean awaitTermination(long timeout, TimeUnit  unit) throws InterruptedException
      阻塞直到所有任务在关闭请求后完成执行,或者发生超时,或者当前线程被中断,以先发生者为准。因为 commonPool() 在程序关闭之前永远不会终止,所以当应用于公共池时,此方法等同于 awaitQuiescence(long, TimeUnit) 但始终返回 false
      参数:
      timeout - 最长时间等待
      unit - 超时参数的时间单位
      返回:
      true 如果此执行程序终止,false 如果超时在终止前结束
      抛出:
      InterruptedException - 如果在等待时被打断
    • awaitQuiescence

      public boolean awaitQuiescence(long timeout, TimeUnit  unit)
      如果由在此池中运行的 ForkJoinTask 调用,则等效于 ForkJoinTask.helpQuiesce() 。否则,等待和/或尝试协助执行任务,直到此池 isQuiescent() 或指示的超时结束。
      参数:
      timeout - 最长时间等待
      unit - 超时参数的时间单位
      返回:
      true 如果静止; false 如果超时已过。
    • close

      public void close()
      除非这是 commonPool() ,否则启动有序关闭,其中执行先前提交的任务,但不会接受新任务,并等待所有任务执行完毕且执行程序终止。

      如果已经终止,或者这是 commonPool() ,则此方法对执行没有影响,并且不会等待。否则,如果在等待时被中断,此方法将停止所有正在执行的任务,就像调用 shutdownNow() 一样。然后它继续等待,直到所有正在执行的任务都完成。等待执行的任务不会执行。在此方法返回之前,中断状态将被重新断言。

      抛出:
      SecurityException - 如果存在安全管理器并且关闭此 ExecutorService 可能会操作不允许调用者修改的线程,因为它不包含 RuntimePermission ("modifyThread") ,或者安全管理器的 checkAccess 方法拒绝访问。
      自从:
      19
    • managedBlock

      public static void managedBlock(ForkJoinPool.ManagedBlocker  blocker) throws InterruptedException
      运行给定的可能阻塞任务。当 ForkJoinPool中运行 时,此方法可能会安排在必要时激活备用线程,以确保当前线程在 blocker.block() 中阻塞时有足够的并行性。

      此方法重复调用 blocker.isReleasable()blocker.block() 直到任一方法返回 true 。每次调用 blocker.block() 之前都会调用返回 falseblocker.isReleasable()

      如果不在 ForkJoinPool 中运行,此方法在行为上等同于

       
       while (!blocker.isReleasable())
        if (blocker.block())
         break; 
      如果在 ForkJoinPool 中运行,池可能首先被扩展以确保在调用 blocker.block() 期间有足够的并行性可用。
      参数:
      blocker - 阻塞任务
      抛出:
      InterruptedException - 如果 blocker.block() 这样做