资讯专栏INFORMATION COLUMN

Executor,Executors和ExecutorService

wdzgege / 3039人阅读

摘要:类提供了一个可扩展的线程池实现。使用举例这里有一个网络服务,其中一个线程池中的线程为请求提供服务。因此返回的中的每个都是完成状态。执行给定的一组任务,如果其中一个任务成功完成没有抛出异常则返回。

Executor

Executor是java.util.concurrent包中的一个接口,是一个执行提交的Runnable任务的对象。这个接口提供了一种方式把任务提交从每个任务会如何执行的方法中解耦,包括线城市用,调度等的细节。使用Executor代替了显式创建线程。例如,比起对一组task中的每一个调用new Thread(new(RunnableTask())).start(),你可以用:

Executor executor = anExecutor;
executor.execute(new RunnableTask1());
executor.execute(new RunnableTask2());
...

但是,Executor接口不是严格需要执行是异步的。在最简单的情况中,一个executor能够在调用者的线程上立即运行提交的任务:

class DirectExecutor implements Executor {
  public void execute(Runnable r) {
    r.run();
  }
}

更典型的是,任务执行在非调用者线程。下面的executor为每个task产出一个新的线程:

class ThreadPerTaskExecutor implements Executor {
  public void execute(Runnable r) {
    new Thread(r).start();
  }
}

很多Executor的实现强制加入了一些关于如何以及何时任务被调度的限制。下面的executor串行提交的任务到第二个executor,表明它是一个混合的executor:

class SerialExecutor implements Executor {
  final Queue tasks = new ArrayDeque();
  final Executor executor;
  Runnable active;

  SerialExecutor(Executor executor) {
    this.executor = executor;
  }

  public synchronized void execute(final Runnable r) {
    tasks.offer(new Runnable() {
      public void run() {
        try {
          r.run();
        } finally {
          scheduleNext();
        }
      }
    });
    if (active == null) {
      scheduleNext();
    }
  }

  protected synchronized void scheduleNext() {
    if ((active = tasks.poll()) != null) {
      executor.execute(active);
    }
  }
}

在java.util.concurrent包中提供的Executor接口的实现(如ThreadPoolExecutorScheduledThreadPoolExecutorForkJoinPoolAbstractExecutorService)也同时实现了ExecutorService,这是一个更广泛的接口。ThreadPoolExecutor类提供了一个可扩展的线程池实现。Executors类为这些Executors提供了方便的工厂方法。

内存一致性效应:线程中在提交一个Runnable对象给一个Executor之前发生的操作happen-before执行这个Runnable(可能在另一个线程中执行)。

实现Executor接口需要实现execute方法,定义如下:

void execute(Runnbale command)

这个方法在未来某个时间点执行给定的command。这个command可能执行在一个新的线程中,在一个池化的线程中,或在调用者线程中,这取决于Executor的实现。

ExecutorService

ExecutorService接口继承Executor接口,是提供管理终止的方法以及produce出Future去跟踪一个或多个异步任务进度的方法的Executor。

一个ExecutorService可以被shutdown,会导致它拒绝新的tasks。提供了两个不同的方法去关闭一个ExecutorService。shutdown方法允许之前提交的任务在终止之前执行,shutdownNow方法禁止等待已经开始任务并试图结束正在执行的任务。如果一个ExecutorService终止了,一个executor没有正在执行的活跃任务,没有等待执行的任务,也没有新任务能被提交。一个没有使用的ExecutorService应该被关闭以回收资源。

submit方法根据Executor的execute(Runnable)方法扩展,创建并返回一个Future,能够用来cancel执行以及等待执行完成。invokeAny方法以及invokeAll方法执行最普通的批量执行,执行一组任务然后等待至少一个,或者所有任务完成。

Executors类为ExecutorService提供工厂方法。

使用举例

这里有一个网络服务,其中一个线程池中的线程为请求提供服务。它使用预配置的Executors的newFixedThreadPool工厂方法:

class NetworkService implements Runnable {
  private final ServerSocket serverSocket;
  private final ExecutorService pool;

  public NetworkService(int port, int poolSize) 
      throws IOException {
    serverSocket = new ServerSocket(port);
    pool = Executors.newFixedTreadPool(poolSize);
  }

  public void run() { // run the service
    try {
      for (;;) {
        pool.execute(new Handler(serverSocket.accept()));
      }
    } catch (IOException ex) {
      pool.shutdown();
    }
  }
}

class Handler implements Runnable {
  private final Socket socket;
  Handler(Socket socket) { this.socket = socket; }
  public void run() {
    // read and service request on socket
  }
}

下面的方法哦通过两步关闭一个ExecutorService,首先调用shutdown以拒绝新来的tasks,然后调用shutdownNow(如果有必要的话),去cancel任何执行的任务:

void shutdownAndAwaitTermination(ExecutorService pool) {
  pool.shutdown(); // Disable new tasks from being submitted
  try {
    // Wait a while for existing tasks to terminate
    if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
      pool.shutdownNow(); // Cancel currently executing tasks
      // Wait a while for tasks to respond to being cancelled
      if (!pool.awaitTermination(60, TimeUnit.SECONDS))
        System.err.println("Pool did not terminate");
    }
  } catch (InterruptedException ie) {
    // (Re-)Cancel if current thread also interrupted
    pool.shutdownNow();
    // Preserve interrupt status
    Thread.currentThread.interrupt();
  }
}
ExecutorService中定义的方法 shutdown
void shutdown()

启动有序关闭,执行先前提交的任务,但是不接受新的任务。如果已经关闭再次执行没有影响。

这个方法不等待先前提交的任务完成执行,使用awaitTermination去等待任务执行完毕。

shutdownNow
List shutdownNow()

试图停止所有正在执行的任务,停止等待任务的处理,返回一个等待执行的任务列表。

这个方法不等待正在执行的任务终止,使用awaitTermination去等待任务终止。

尽力(best-effort)去停止正在执行的任务。例如,标准实现会通过Thread的interrupt去cancel任务,因此任何回应终止失败的任务永远不会终止。

isShutdown
boolean isShutdown()

如果executor已经被shutdown则返回true。

isTerminated
boolean isTerminated()

如果所有任务在shutdown之后都执行完成则返回true。注意isTerminated永远不会为true除非shutdown或shutdownNow先执行。

awaitTermination
boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException

在一个shutdown请求后阻塞直到所有任务完成执行,或者timeout发生,或者当前线程被interrupt,看哪个先发生。

submit
 Future submit(Callable task)

提交一个返回值的任务去执行并返回一个代表任务挂起结果的Future对象。Future的get方法会返回成功完成的任务结果。

如果你想要立即阻塞等待一个任务完成,你可以使用result = exec.submit(aCallable).get()

submit
 Future submit(Runnable task, T result)

提交一个Runnable任务去执行并返回一个代表这个任务的Future。Future的get方法会返回成功完成的任务结果。

submit
Future submit(Runnable task)

提交一个Runnable任务去执行并返回一个代表这个任务的Future。Future的get方法会返回成功完成的任务结果null。

invokeAll
 List> invokeAll(Collection> tasks) 
    throws InterruptedException

执行给定的一组任务,返回一个包含这些任务状态和结果的Future列表。Future的isDone方法对返回列表中的每个元素调用都返回true。

这个方法会阻塞,等待所有task完成。因此返回的list中的每个Future都是完成状态。

invokeAll
 List> invokeAll(Collection> tasks,
                              long timeout, TimeUnit unit)
       throws InterruptedException

执行给定的一组任务,返回一个包含这些任务状态和结果的列表。所有任务完成或timeout超时时方法返回。Future的isDone方法对返回列表中的每个元素调用都返回true。

返回后,没有完成的任务被cancel。

invokeAny
 T invokeAny(Collection> tasks)
      throws InterruptedException, ExcutionException

执行给定的一组任务,如果其中一个任务成功完成(没有抛出异常)则返回。返回后,所有没完成的任务都被cancel。

invokeAny
 T invokeAny(Collection> tasks, long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException

执行给定的一组任务,如果其中一个任务成功完成(没有抛出异常)则返回。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/75979.html

相关文章

  • 初读《Java并发编程的艺术》-第十章:Executor框架 -10.1 Executor框架简介

    摘要:线程的启动与销毁都与本地线程同步。操作系统会调度所有线程并将它们分配给可用的。框架的成员主要成员线程池接口接口接口以及工具类。创建单个线程的接口与其实现类用于表示异步计算的结果。参考书籍并发编程的艺术方腾飞魏鹏程晓明著 在java中,直接使用线程来异步的执行任务,线程的每次创建与销毁需要一定的计算机资源开销。每个任务创建一个线程的话,当任务数量多的时候,则对应的创建销毁开销会消耗大量...

    aisuhua 评论0 收藏0
  • Java 8 并发: Threads Executors

    摘要:能够异步的执行任务,并且通常管理一个线程池。这样我们就不用手动的去创建线程了,线程池中的所有线程都将被重用。在之后不能再提交任务到线程池。它不使用固定大小的线程池,默认情况下是主机的可用内核数。 原文地址: Java 8 Concurrency Tutorial: Threads and Executors Java 5 初次引入了Concurrency API,并在随后的发布版本中...

    J4ck_Chan 评论0 收藏0
  • Java多线程进阶(三九)—— J.U.C之executors框架:executors框架概述

    摘要:注意线程与本地操作系统的线程是一一映射的。固定线程数的线程池提供了两种创建具有固定线程数的的方法,固定线程池在初始化时确定其中的线程总数,运行过程中会始终维持线程数量不变。 showImg(https://segmentfault.com/img/bVbhK58?w=1920&h=1080); 本文首发于一世流云专栏:https://segmentfault.com/blog... ...

    wdzgege 评论0 收藏0
  • Java 8 并发教程:线程执行器

    摘要:在这个示例中我们使用了一个单线程线程池的。在延迟消逝后,任务将会并发执行。这是并发系列教程的第一部分。第一部分线程和执行器第二部分同步和锁第三部分原子操作和 Java 8 并发教程:线程和执行器 原文:Java 8 Concurrency Tutorial: Threads and Executors 译者:BlankKelly 来源:Java8并发教程:Threads和Execut...

    jsdt 评论0 收藏0
  • 线程池源码分析

    摘要:线程池的作用线程池能有效的处理多个线程的并发问题,避免大量的线程因为互相强占系统资源导致阻塞现象,能够有效的降低频繁创建和销毁线程对性能所带来的开销。固定的线程数由系统资源设置。线程池的排队策略与有关。线程池的状态值分别是。 线程池的作用 线程池能有效的处理多个线程的并发问题,避免大量的线程因为互相强占系统资源导致阻塞现象,能够有效的降低频繁创建和销毁线程对性能所带来的开销。 线程池的...

    enda 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<