JAVA并发编程笔记(二)---Executor框架

一:简介

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

Executor是一个灵活而且强大的框架的基础,可以用于异步任务执行,而且支持很多不同类型的任务执行策略。它还为任务提交和任务执行之间的解耦提供了标准方法。为使用Runnable描述任务提供了通用的方式。Executor的实现提供了对生命周期的支持以及钩子函数,可以添加统计收集、应用程序管理机制和监视器等扩展。

Executor基于生产者-消费者模式。提交任务的执行者是生产者,执行任务的线程是消费者,使用Executor设计生产者-消费者模式最简单。

当你想为任务制定执行策略时,Executor更加灵活和适用。执行策略指明了:任务在什么线程中执行,以什么顺序执行(FIFO、LIFO、优先级),有多少任务并发执行,有多少个任务可以进入等待执行队列等等。

二:线程池

 线程池管理一个工作者线程的同构池(就是一个池子里面放的是各个线程),它的优势是每次任务过来不用重新创建线程,直接从池子里获取,节省了一定得开销,合适大小的线程池能大大提高响应性。

Executors提供了多种类型线程池的创建。

public class Executors {
    //创建定长的线程池 没提交一个任务就创建一个线程 直至到达最大值保持不变
    //(一个线程由于非预期异常结束,会补充一条新的线程)
    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
    public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>(),
                                      threadFactory);
    }
    //创建一个可缓存的线程池 如果当前长度超过处理的需要时,可以灵活回收空闲线程,
    //需求增加时,灵活添加新线程,不会对池子的长度做任何限制。
    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
    public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>(),
                                      threadFactory);
    }
    //创建一个单线程的Executor,它只创建唯一的工作者线程来执行任务,如有异常会有另外一个线程替代
    //它会保证依照任务队列规定的顺序执行。
    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
    public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>(),
                                    threadFactory));
    }
    //创建一个定长线程池,支持定时的以及周期性的任务执行
    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }
    public static ScheduledExecutorService newScheduledThreadPool(
            int corePoolSize, ThreadFactory threadFactory) {
        return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
    }

}

三:Executors的生命周期

Executor实现通常只是为执行任务而创建线程,但JVM会在所有线程都终止后才退出,如果无法正确关闭Executor,将会阻止JVM的结束。因为Executor是异步地执行任务,所以在任何时间里,所有之前提交的任务的状态都是不能立即可见的。为了解决这个问题,ExecutorService扩展了Executor并且添加了一些用于生命周期管理的方法。

public interface ExecutorService extends Executor {
    void shutdown();
    List<Runnable> shutdownNow();
    boolean isShutdown();
    boolean isTerminated();
    boolean awaitTermination(long timeout, TimeUnit unit)
        throws InterruptedException;
    <T> Future<T> submit(Callable<T> task);
    <T> Future<T> submit(Runnable task, T result);
    Future<?> submit(Runnable task);
    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
        throws InterruptedException;
    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                  long timeout, TimeUnit unit)
        throws InterruptedException;    
    <T> T invokeAny(Collection<? extends Callable<T>> tasks)
        throws InterruptedException, ExecutionException;    
    <T> T invokeAny(Collection<? extends Callable<T>> tasks,
                    long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

ExecutorService暗示生命周期的三种状态,运行,关闭,终止。ExecutorService创建后的初始状态是运行状态,shutdow方法会启用一个平缓的关闭过程:停止接收新线程,同时等待已经提交的任务完成(包括尚未执行的任务)。shutdowNow方法启用一个强制的关闭过程:尝试取消所有运行中的任务和在队列中尚未开始的任务。

在关闭后提交到ExecutorService中的任务,会被拒绝执行处理器处理(Rejected Execution Handler),拒绝执行处理器可能只是简单的放弃任务,也可能会引起executor抛出一个未检查的RejectedExecutionException。

四:可携带结果的任务:Callable和Future

  Executor框架使用Runnable作为其任务的基本表达形式,Runnable不能返回一个值或者抛出受检查的异常。很多任务都会引起严重的计算延迟,对于这样的任务Callable是最佳的抽象,它在进入主进入点-call方法等待返回值,并为可能抛出的异常预先做好了准备。

@FunctionalInterface
public interface Callable<V> {
   
    V call() throws Exception;
}

Future描述了任务的生命周期,并提供了相关的方法来获取任务的结果,取消任务以及检验任务是否已经完成还是取消。如果任务没有完成,get会阻塞直到它完成。如果任务抛出异常,get方法会将异常封装成ExecutionException,然后重新抛出;如果任务取消,get方法会抛出CancellationException。

ExecutorService中所有的submit方法都返回一个Future,因此可以将Runnable或Callable提交给executor,然后得到一个Future,用它来重新获取任务执行的结果,或者取消任务。也可以显示为Runnable或Callable实例化一个FutureTask(FutureTask实现了Runnable,所以既可以将它交给Executor执行,又可以直接调用run方法运行)。

五:CompletionService

如果你向Executor提交了一个批处理任务,并且希望在他们完成后获得结果。这个时候可以使用完成服务(Completion Service),CompletionService整合了Executor和BlockingQueue的功能,你可以将Callable任务交给它执行,然后使用类似于队列中的take和poll方法,在结果完整可用时获得这个结果,

ExecutorCompletionService是CompletionService的一个实现,它在构造函数中创建一个BlockingQueue,用它保存完成的结果。计算完成会调用FutureTask中的done方法,当提交一个任务后,首先把这个任务包装为一个QueueingFuture,他是Future的一个子类,然后复写done方法,将结果置入BlockingQueue中。take和poll方法委托给了BlockingQueue,它会在结果不可用时阻塞。

public class ExecutorCompletionService<V> implements CompletionService<V> {
    private final Executor executor;
    private final AbstractExecutorService aes;
    private final BlockingQueue<Future<V>> completionQueue;

   
    private class QueueingFuture extends FutureTask<Void> {
        QueueingFuture(RunnableFuture<V> task) {
            super(task, null);
            this.task = task;
        }
        protected void done() { completionQueue.add(task); }
        private final Future<V> task;
    }

    private RunnableFuture<V> newTaskFor(Callable<V> task) {
        if (aes == null)
            return new FutureTask<V>(task);
        else
            return aes.newTaskFor(task);
    }

    private RunnableFuture<V> newTaskFor(Runnable task, V result) {
        if (aes == null)
            return new FutureTask<V>(task, result);
        else
            return aes.newTaskFor(task, result);
    }

   
    public ExecutorCompletionService(Executor executor) {
        if (executor == null)
            throw new NullPointerException();
        this.executor = executor;
        this.aes = (executor instanceof AbstractExecutorService) ?
            (AbstractExecutorService) executor : null;
        this.completionQueue = new LinkedBlockingQueue<Future<V>>();
    }

    
    public ExecutorCompletionService(Executor executor,
                                     BlockingQueue<Future<V>> completionQueue) {
        if (executor == null || completionQueue == null)
            throw new NullPointerException();
        this.executor = executor;
        this.aes = (executor instanceof AbstractExecutorService) ?
            (AbstractExecutorService) executor : null;
        this.completionQueue = completionQueue;
    }

    public Future<V> submit(Callable<V> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<V> f = newTaskFor(task);
        executor.execute(new QueueingFuture(f));
        return f;
    }

    public Future<V> submit(Runnable task, V result) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<V> f = newTaskFor(task, result);
        executor.execute(new QueueingFuture(f));
        return f;
    }

    public Future<V> take() throws InterruptedException {
        return completionQueue.take();
    }

    public Future<V> poll() {
        return completionQueue.poll();
    }

    public Future<V> poll(long timeout, TimeUnit unit)
            throws InterruptedException {
        return completionQueue.poll(timeout, unit);
    }

}

六:总结

围绕任务的执行来构造应用程序,可以简化开发,便于同步。Executor框架有助于你在任务的提交与任务的执行策略之间进行解耦,同时还支持很多不同类型的执行策略。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值