任务执行(第六章)

任务执行

任务边界:当围绕“任务执行”来设计应用程序时,第一步就是要找出清晰的任务边界。缓存

1.为每一个任务建立一个线程的风险:

  1. 线程生命周期的开销很是高:线程的建立于销毁并发

  2. 资源消耗:活跃的线程会消耗系统资源,尤为是内存。若是可运行的线程数量多于可用处理器的数量,那么有些线程将闲置。因此,若是已经拥有足够多的线程使CPU保持忙碌状态,那么建立再多的线程反而会下降性能框架

  3. 稳定性:在可建立线程的数量上存在必定限制,这个闲置值将随平台的不一样而不一样,而且受多个因素闲置。若是破坏了这些限制,那么可能抛出OutOfMemoryError异常函数

    应该对程序中建立的线程数量进行限制。

2. Executor框架

在Java中,执行任务的主要抽象不是Thread,而是Executor。
public interface Executor {
   	void execute(Runnable command);
}

Executor框架能支持多种不一样类型的任务执行策略,它提供了一种标准的方法将任务的提交过程与执行过程解耦,并用Runnable来表示任务。Executor的实现还提供了对生命周期的支持,以及统计信息收集、应用程序管理机制和性能监视等机制。 Executor基于生产者----消费者模式,提交任务的操做至关于生产者,执行任务的线程至关于消费者。性能

  1. Executor的生命周期

JVM只有在全部(非守护)线程都终止后才会退出,所以,若是Executor没有正确关闭,那么JVM将没法退出。 Executor执行的任务有4个证实周期阶段:建立、提交、开始和完成。已提交但还没有开始的任务能够取消,但对于已经开始执行的任务,只有当他们响应中断时才能取消。 Executor扩展了ExecutorService接口,用于管理生命周期:线程

//Executor的生命周期有3中运行状态:运行、关闭和已终止。
public interface ExecutorService extends Executor {
	/*shutdown执行平稳的关闭过程:再也不接受新任务,同时等待已提交的任务执行完----包括那些还未开始执行的任务*/
	void shutdown();
    /*shutdownNow将执行粗暴的关闭过程:它将尝试取消全部运行中的任务,而且再也不启动队列中还没有开始执行的任务*/
    List<Runnable> shutdownNow();
    boolean isShutdown();
    boolean isTerminated();
    boolean awaitTermination(long timeout,TimeUnit unit) throws InterruptedExecutor;
}

Executor的缺陷:设计

  1. Executor使用Runnable做为基本的任务标志形式,但Runnable中的run()不能返回值也不能抛出异常

3.执行策略

在执行策略中定义了任务执行的“What、Where、When、How”等方面。包括: 1. 在什么(what)线程中执行 2. 任务按照什么顺序(FIFO、LIFO、优先级)执行 3. 有多少个(how many)任务能并发执行 4. 在队列中有多少个(how many)任务等待执行 5. 若是系统因为过载而须要拒绝一个任务,那么应该选择哪个(which)任务?另外如何(how)通知应用程序有任务被拒绝 6. 在执行一个任务以前或以后,应该进行哪些(what)动做code

4.线程池

线程池指管理一组同构工做线程的资源池。 能够经过调用Executor中的一些静态函数建立线程池:对象

  1. newFixedThreadPool:建立一个固定长度的线程池,每当提交一个任务时就建立一个线程,直到建立的线程数量达到最大,此后线程的数量不会再变化。若是某个线程因为发生未预期的Exception而结束,那么线程会补充一个新的线程排序

  2. newCachedThreadPool:建立一个可缓存的线程池,若是线程池的规模超过了处理需求,那么将回收空闲的线程,而当需求增长时,则能够添加新的线程,线程池的规模不存在人任何限制

  3. newSingleThreadExecutor:单线程的Executor,它建立单个工做者线程来执行任务,若是这个线程异常结束,会建立一个新的线程来代替,其能确保依照任务在队列中的顺序串行序执行

  4. new ScheduledThreadPool:建立一个固定长度的线程池,并且以延时或定时的方式来执行顺序

    “在线程池中执行任务”要比“为每一个任务分配一个线程”优点更多。

5.延迟任务与周期任务

Timer类负责管理延迟任务以及周期任务,可是Timer类存在一些缺陷,应该考虑使用ScheduledThreadPool类代替它Timer类的缺陷

  1. Timer在执行全部定时任务时只会建立一个线程,若是某个任务的延时时间过长,那么将破坏其余TimerTask的定时精确性。

  2. 若是TimerTask抛出了一个未受检查的异常,因为Timer线程并不捕获异常,所以Timer将终止线程的执行。

    若是要构建本身的调度服务,那么可使用DelayQueue,它实现了BlockingQueue,并为ScheduledThreadPoolExecutor提供调度功能。DelayQueue管理着一组Delayed对象,每一个Delayed对象都有一个相应的延迟时间:在DelayQueue中,只有某个元素逾期后,才能从DelayQueue中执行take操做,从DelayQueue中返回的对象将根据他们的延迟时间进行排序。

6.Callable与Future

Callable提供了一种相比Runnable更好的抽象:call,call()有返回值(要用Callable表示无返回值的任务,使用Callable<void>),而且容许抛出异常。 Future表示一个任务的生命周期,并提供了相应的方法来判断是否已经完成或取消,以及获取任务的结果和取消任务等。Future意味着任务的生命周期只能前进,不能后退。 若是任务抛出了异常,那么get将异常封装为ExecutorException并从新抛出,而且能够经过getCause来得到被封装的初始异常,若是任务被取消,那么get将抛出 CancellationException

public interface Callable<V> {
	V call() throws Exception;
}
public interface Future<V> {
	boolean cancel(boolean mayInterruptIfRunning);
    boolean isCancelled();
    boolean isDone();
    V get() throws InterruptedException,ExecutionException,
    		CancellationException;
    V get(long timeOut,TimeUnit unit) throws InterruptedException,ExecutionException,
    		CancellationException,TimeoutException;
}
只有当大量相互独立且同构的任务能够并发处理时,才能体现出将程序的工做负载分配到多个任务中带来的性能提高。
相关文章
相关标签/搜索