zoukankan      html  css  js  c++  java
  • JDK线程池的实现

    线程池

    接口Executor

    该接口只有一个方法,JDK解释如下

    执行已提交的Runnable 任务的对象。此接口提供一种将任务提交与每个任务将如何运行的机制(包括线程使用的细节、调度等)分离开来的方法。

    不过,Executor 接口并没有严格地要求执行是异步的。在最简单的情况下,执行程序可以在调用者的线程中立即运行已提交的任务:

    更常见的是,任务是在某个不是调用者线程的线程中执行的。以下执行程序将为每个任务生成一个新线程。

    方法介绍如下:

    void execute(Runnable command)

    在未来某个时间执行给定的命令。该命令可能在新的线程、已入池的线程或者正调用的线程中执行,这由Executor 实现决定。

    接口ExecutorService

    ExecutorService 是对 Executor 的扩展,JDK文档解释如下:

    Executor 提供了管理终止的方法,以及可为跟踪一个或多个异步任务执行状况而生成 Future 的方法。

    可以关闭ExecutorService,这将导致其拒绝新任务。提供两个方法来关闭 ExecutorServiceshutdown() 方法在终止前允许执行以前提交的任务,而 shutdownNow()方法阻止等待任务启动并试图停止当前正在执行的任务。在终止时,执行程序没有任务在执行,也没有任务在等待执行,并且无法提交新任务。应该关闭未使用的 ExecutorService 以允许回收其资源。

    通过创建并返回一个可用于取消执行和/或等待完成的 Future,方法 submit 扩展了基本方法 Executor.execute(java.lang.Runnable)。方法 invokeAny invokeAll 是批量执行的最常用形式,它们执行任务 collection,然后等待至少一个,或全部任务完成(可使用 ExecutorCompletionService 类来编写这些方法的自定义变体)。

    此接口中的关键是三个submit 方法,接受一个任务,并返回结果Future

    • <T> Future<T> submit(Callable<T> task);
    • <T> Future<T> submit(Runnable task, T result);
    • Future<?> submit(Runnable task);

     

    任务执行

    Submit 的实际代码位于AbstractExecutorService,继承ExecutorService。来观察其三个submit方法。 不论submit 方法的参数是什么,都是先构造一个RunnableFuture ,然偶执行它,并返回它。执行和返回的都是RunnableFuture。所以RunnableFuture实现了future 接口和runnnable接口。注意这点的类型是RunnableFuture,所有接下来的execute方法执行的run方法是RunnableFuture 的具体实现类FutureTaskrun方法。

    来看RunnableFuture,其代码如下:

    作为 Runnable Future。成功执行 run 方法可以完成 Future 并允许访问其结果。以下代码可以看出 返回的实际上是FutureTask,RunnableFuture的实现类。

    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {

    return new FutureTask<T>(runnable, value);}

    关于 FutureTask JDK对其介绍如下:

    可取消的异步计算。利用开始和取消计算的方法、查询计算是否完成的方法和获取计算结果的方法,此类提供了对Future 的基本实现。仅在计算完成时才能获取结果;如果计算尚未完成,则阻塞 get 方法。一旦计算完成,就不能再重新开始或取消计算。

    可使用FutureTask 包装 Callable Runnable 对象。因为 FutureTask 实现了 Runnable,所以可将 FutureTask 提交给 Executor 执行。

    除了作为一个独立的类外,此类还提供了 protected 功能,这在创建自定义任务类时可能很有用。

    先看其构造函数。可以看出其构造函数主要是一个 同步器的构造。同步器接受一个Callable类型的参数。

    对于参数是Runnable 类型时,经过转化为Callable 类型,转化代码如下,本质上就是在Callable call方法中调用Runnablerun方法:

    FutureTask的关键逻辑都由他的一个内部类Sync 实现。我们先暂且不管其具体实现,留在后面说。

    执行

    具体的逻辑如下描述:

    首先判断空;

    如果当前池大小 小于 核心池大小(初始就是这样),那么会执行 addIfUnderCorePoolSize这个方法。这个方法就会创建新的工作线程,且把当前任务 command 设置为他的第一个任务,并开始执行,返回true。整个execute方法结束。

    1. 否则加入到等待队列中。

      2)只有当前池大小小于核心池大小的时候,且线程池处于RUNNING状态的时候才增加新的工作线程,并把传进来的任务作为第一个任务并开始执行。此时返回真,否则返回假。

      如果当前池大小 大于核心池的大小,或者添加新的工作线程失败(这可能是多线程环境下,竞争锁,被阻塞,其他线程已经创建好了工作线程)。那么当前任务进入到等待队列。

      如果队列满,或者线程池已经关闭,那么拒绝该任务。

       

       

      FutureTask

      此类是RunnableFuture的实现类。线程池执行的run方法是它的run方法。它委托给Sync实现,SYNC 继承AQS

      重点看Sync。对具体任务的调用发生在innerSet(callable.call());这句调用,innerSet的方法 作用是 设置get方法的返回值。

      get方法是需要获取锁的,所以在具体的任务没有执行完前,调用get方法会进入到阻塞状态。

  • 相关阅读:
    nginx重启失败的解决方法
    Linux开机禁用开启防火墙
    Linux查看系统版本信息的几种方法
    Linux修改时区的正确方法
    Linux中awk的gsub函数用法
    Linux 的mktemp 命令详解
    tomcat的简单概要小结
    {面试题8: 旋转数组的最小数字}
    {面试题7: 使用两个队列实现一个栈}
    {面试题7: 用两个栈实现队列}
  • 原文地址:https://www.cnblogs.com/jiumao/p/7137561.html
Copyright © 2011-2022 走看看