Executor框架和线程池

来源:互联网 发布:中国高铁功臣 知乎 编辑:程序博客网 时间:2024/06/05 21:55

在JDK5后主要提供的多线程处理都在java.util.concurrent包中,多线程的主要抽象不是Thread,而是Executor,Executor为接口,定义在java.util.concurrent包下,只定义了一个方法:

public interface Executor {      void execute(Runnable command);  }  

它提供了一种标准的方法将任务的提交和过程和执行过程解耦,并用Runnable来表示任务,Executor的实现还提供了对生命周期的支持,以及统计信息收集、应用程序管理机制和性能监视机制。Executor基于生产者——消费者模式,提交任务的过程就相当于是生产者,生成待完成的工作单元,执行任务的过程相当于消费者,执行完这些工作单元。如果在程序中实现一个生产者——消费者的设计,那么最简单的方法就使用Executor。每当看到下面这种形式的代码:new Thread(runnable).start(),最好考虑使用Executor来代替更加灵活。

线程池

线程池指管理一组同构工作线程的资源池,线程池是与工作队列密切相关的,在工作队列中保存了所有等待执行的任务,工作者线程的任务很简单:从工作队列中获取一个任务,执行任务,然后返回线程池并等待下一个任务。“在线程池中执行任务”比“为每个任务分配一个线程”有更大优势,通过重用现有线程,而不是创建新线程,可以在处理多个请求时分摊在线程创建和销毁过程中产生的巨大的开销,另外,当请求到达时,工作线程已经存在,因此不会由于等待创建线程而延迟任务的执行,从而提高响应性,通过调整线程池的大小,可以创建足够多的线程以便使处理器保持忙碌的状态,同时还可以防止过多的线程相互竞争资源而应用程序耗尽内存。

无限制创建线程的不足

1、线程生命周期的开销非常高。线程的创建也销毁并不是没有代价的,根据平台的不同实际开销也不同,但线程的创建过程都需要时间,延迟请求的处理,并且需要JVM和操作系统提供一些辅助操作。
2、资源消耗。活跃的线程会消耗系统资源,特别是内存,如果可以运行的线程数量多于可用的处理器数量,那么有些线程就会闲置,大量的闲置线程就会占用很多的内存,如果你已经有足够多的线程使处理器保持忙碌状态,那么创建更多的线程反而会降低性能。
3、稳定性。在可创建线程的数量上存在一个限制,不同平台不同,而且受多个因素制约,包括JVM启动参数、Thread构造函数中请求的栈大小,以及底层操作系统对线程的限制等,如果破坏了这些限制将抛出OutOfMemoryError异常。

Executor的生命周期

为了解决执行服务的生命周期问题,ExecutorService扩展了Executor接口,添加了一些用于生命周期的管理方法,下面代码为ExecutorService接口的定义:

public interface ExecutorService extends Executor {      void shutdown();      List<Runnable> shutdownNow();      boolean isShutdown();      boolean isTerminated();      boolean awaitTermination(long timeout, TimeUnit unit)          throws InterruptedException;      ......  }  

ExecutorService有三种状态:运行、关闭、终止,ExecutorService在初建时属于运行状态,shutdown方法将执行平缓的关闭过程:不再接受新的任务,同时等待已经提交的任务执行完成,包括那些还未开始执行的任务。shotdownNow()方法将粗暴的关闭过程:它将尝试取消所有运行中的任务,并且不再启动队列中尚未开始执行的任务。

0 0
原创粉丝点击