Executor源码浅析

5 篇文章 0 订阅
3 篇文章 0 订阅

Executor

该类用来执行提交的任务,对任务提交任务执行之间进行解耦,任务执行的细节包括线程的使用、调度等。通常使用Executor而不是明确地创建线程。
Executor的源码如下:

public interface Executor {

    /**
     * 在未来一定时间内执行给出的命令,这个命令可能在新线程、线程池的线程、调用线程执行,这取决于Executor的实现。
     */
    void execute(Runnable command);
}

例如,相比创建线程,然后让他执行:

new Thread(new(RunnableTask())).start()

可以这样使用Executor类:

Executor executor = ...	//得到一个Executor对象
executor.execute(new RunnableTask1()); //将一个Runnable对象传入execute方法
executor.execute(new RunnableTask2());
...

Executor并不严格要求任务执行是异步的。最简单的情况下,提交的任务可以在调用者的线程执行:

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

更典型的情况下,任务在其他线程执行,而不是在调用者的线程:

class ThreadPerTaskExecutor implements Executor {
  //为每个任务创建一个线程
  public void execute(Runnable r) {
    new Thread(r).start();
  }
}

许多Executor的实现类对任务何时执行、怎样执行实施一些限制。如下的Executor将提交的任务序列化到另一个executor,这是一个复合的executor

class SerialExecutor implements Executor {
  final Queue<Runnable> tasks = new ArrayDeque<Runnable>();
  final Executor executor;
  Runnable active;
  SerialExecutor(Executor executor) {
    this.executor = executor;
  }
  public synchronized void execute(final Runnable r) {
    tasks.offer(new Runnable() {	//用一个Runnable封装参数给出的Runnable r,并放到tasks队列中
      public void run() {
        try {
          r.run();
        } finally {
          scheduleNext();	//外层封装的Runnable在运行结束时调度下一个任务
        }
      }
    });
    if (active == null) {
      scheduleNext();
    }
  }
  protected synchronized void scheduleNext() {
    if ((active = tasks.poll()) != null) {	//如果还有任务,就对他进行调度
      executor.execute(active);
    }
  }
}

ExecutorService

这个接口提供了终止线程跟踪异步任务进度的方法。它继承了Executor接口:

public interface ExecutorService extends Executor {

该接口包含的方法:

/**
  * 启动有序关闭,在此过程中执行以前提交的任务,但不接受任何新任务。
  * 此方法不会等待以前提交的任务执行完成。用awaitTermination来等待任务执行完成。
  */
void shutdown();

/**
  * 停止所有正在执行的任务,停止处理正在等待的任务,并返回一个等待执行的任务列表。
  */
List<Runnable> shutdownNow();

/**
  * 判断线程池是否已经关闭。
  */
boolean isShutdown();

/**
  * 当线程池调用shutdown后,判断线程池的所有任务是否都已完成。
  */
boolean isTerminated();

/**
  * 调用后将会shutdown线程池,然后阻塞直至所有任务完成/超时/当前线程被中断。
  */
boolean awaitTermination(long timeout, TimeUnit unit)
        throws InterruptedException;

/**
  * 提交一个具有返回值的任务执行。返回的Future对象代表将来计算完成得到的结果。
  */
<T> Future<T> submit(Callable<T> task);

/**
  * 执行给出的任务,并返回Future对象的列表
  */
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException;

/**
  * 执行给出的任务,并返回第一个已完成执行的Future对象
  */
<T> T invokeAny(Collection<? extends Callable<T>> tasks)
        throws InterruptedException, ExecutionException;

其中submit方法既可以接受一个Runnable也可以接受一个Callable,并且返回一个代表计算结果的Future;而继承自Executorexecute方法只能接受一个Runnable,它没有返回值。
以上方法还有几种重载形式,在此不再赘述。

AbstractExecutorService

这个抽象类是ExecutorService的默认实现。

public abstract class AbstractExecutorService implements ExecutorService {

    /**
     * 为给出的Runnable对象和默认返回值返回一个RunnableFuture对象
     */
    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
        return new FutureTask<T>(runnable, value);
    }

    /**
     * 为给出的Callable对象任务返回一个RunnableFuture对象
     */
    protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
        return new FutureTask<T>(callable);
    }

    /**
     * 提交一个没有返回值任务,submit方法直接调用了execute方法执行任务
     */
    public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<Void> ftask = newTaskFor(task, null);
        execute(ftask);
        return ftask;
    }

    /**
     * 提交一个Runnable对象描述的任务,并且带有返回值
     */
    public <T> Future<T> submit(Runnable task, T result) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task, result);
        execute(ftask);
        return ftask;
    }

    /**
     * 提交一个callable对象描述的任务
     */
    public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }

    /**
     * 这是invokeAny的主要实现方法
     */
    private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks,
                              boolean timed, long nanos)
        throws InterruptedException, ExecutionException, TimeoutException {
        if (tasks == null)
            throw new NullPointerException();
        int ntasks = tasks.size();
        if (ntasks == 0)
            throw new IllegalArgumentException();
        ArrayList<Future<T>> futures = new ArrayList<Future<T>>(ntasks);
        //ExecutorCompletionService能够用提供的Executor执行任务,这个类将提交的任务在完成后放置到一个队列中,并使用take方法进行访问
        ExecutorCompletionService<T> ecs =
            new ExecutorCompletionService<T>(this);	

        // 为了提高效率,特别是在并行能力有限的executor中,在提交更多任务之前,检查先前提交的任务是否已经完成
        try {
            // 记录异常,如果获取结果失败,就抛出最近的一个异常
            ExecutionException ee = null;
            final long deadline = timed ? System.nanoTime() + nanos : 0L;
            Iterator<? extends Callable<T>> it = tasks.iterator();

            // 先开始第一个任务
            futures.add(ecs.submit(it.next()));
            --ntasks;
            int active = 1;

for (;;) {
                Future<T> f = ecs.poll();
                if (f == null) {    //队列为空
                    if (ntasks > 0) {
                        --ntasks;
                        futures.add(ecs.submit(it.next())); //继续提交任务
                        ++active;
                    }
                    else if (active == 0)   //没有活跃的线程了就退出循环
                        break;
                    else if (timed) {   //如果任务计时,则如果在指定时间内仍poll出一个null,说明任务还没完成,抛出异常
                        f = ecs.poll(nanos, TimeUnit.NANOSECONDS);
                        if (f == null)
                            throw new TimeoutException();
                        nanos = deadline - System.nanoTime();   //剩余时间
                    }
                    else
                        f = ecs.take();
                }
                if (f != null) {    //有新的任务完成了
                    --active;
                    try {
                        return f.get(); //从future对象获取返回值返回
                    } catch (ExecutionException eex) {
                        ee = eex;
                    } catch (RuntimeException rex) {
                        ee = new ExecutionException(rex);
                    }
                }
            }

            if (ee == null)
                ee = new ExecutionException();
            throw ee;

        } finally {
            for (int i = 0, size = futures.size(); i < size; i++)
                futures.get(i).cancel(true);    //退出前取消任务
        }
    }

	/**
	  * 执行给出的任务,并返回第一个已完成执行的Future对象
	  */
    public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
        throws InterruptedException, ExecutionException {
        try {
            return doInvokeAny(tasks, false, 0);
        } catch (TimeoutException cannotHappen) {
            assert false;
            return null;
        }
    }
	
    public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
                           long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException {
        return doInvokeAny(tasks, true, unit.toNanos(timeout));
    }

    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
        throws InterruptedException {
        if (tasks == null)
            throw new NullPointerException();
        ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
        boolean done = false;
        try {
            for (Callable<T> t : tasks) {
                RunnableFuture<T> f = newTaskFor(t);
                futures.add(f);
                execute(f);
            }
            for (int i = 0, size = futures.size(); i < size; i++) {
                Future<T> f = futures.get(i);
                if (!f.isDone()) {  //如果当前任务还没完成就阻塞
                    try {
                        f.get();    //get方法能够使当前线程阻塞直到任务完成
                    } catch (CancellationException ignore) {
                    } catch (ExecutionException ignore) {
                    }
                }
            }
            done = true;
            return futures;
        } finally {
            if (!done)  //如果没有完成全部任务,说明抛出了未捕获异常,取消所有任务
                for (int i = 0, size = futures.size(); i < size; i++)
                    futures.get(i).cancel(true);
        }
    }

    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                         long timeout, TimeUnit unit)
        throws InterruptedException {
        if (tasks == null)
            throw new NullPointerException();
        long nanos = unit.toNanos(timeout);
        ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
        boolean done = false;
        try {
            for (Callable<T> t : tasks)
                futures.add(newTaskFor(t));

            final long deadline = System.nanoTime() + nanos;
            final int size = futures.size();

            // Interleave time checks and calls to execute in case
            // executor doesn't have any/much parallelism.
            for (int i = 0; i < size; i++) {
                execute((Runnable)futures.get(i));
                nanos = deadline - System.nanoTime();
                if (nanos <= 0L)
                    return futures;
            }

            for (int i = 0; i < size; i++) {
                Future<T> f = futures.get(i);
                if (!f.isDone()) {
                    if (nanos <= 0L)
                        return futures;
                    try {
                        f.get(nanos, TimeUnit.NANOSECONDS);	//限定执行时间,如果超时就抛出TimeoutException
                    } catch (CancellationException ignore) {
                    } catch (ExecutionException ignore) {
                    } catch (TimeoutException toe) {
                        return futures;	//超时直接将futures容器返回
                    }
                    nanos = deadline - System.nanoTime();	//计算剩余时间
                }
            }
            done = true;
            return futures;
        } finally {
            if (!done)
                for (int i = 0, size = futures.size(); i < size; i++)
                    futures.get(i).cancel(true);
        }
    }

}

使用Executor类的优点

如果不用Executor类,任务的提交和执行策略耦合,如下:

class ThreadPerTaskWebServer {
    public static void main(String[] args) throws IOException {
        ServerSocket socker = new ServerSocket(80);
        while(true) {
            final Socket connection = socker.accept();
            Runnable task = new Runnable() {
                @Override
                public void run() {
                    handleRequest(connection);
                }
            };
            //为每个任务创建一个线程
            new Thread(task).start();
        }
    }

    private static void handleRequest(Socket connection) {
        //...
    }
}

在Java类库中,任务执行的主要抽象不是Thread,而是Executor
以下例子用Executor决定具体的执行策略:

class TaskExecutorWebServer {
    private static final int NTHREADS = 100;
    //通过选择具体的Executor决定执行策略
    private static final Executor exec = Executors.newFixedThreadPool(NTHREADS);

    public static void main(String[] args) throws IOException {
        ServerSocket socker = new ServerSocket(80);
        while(true) {
            Socket conn = socker.accept();
            Runnable task = new Runnable() {
                @Override
                public void run() {
                    handleRequest(conn);
                }
            };
            exec.execute(task);
        }
    }

    private static void handleRequest(Socket conn) {
        //...
    }
}

如果仍想为每个请求创建一个线程,也可以用Executor实现,只需实现Executor接口:

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

于是,当出现如下代码:

new Thread(runnable).start();

并且希望得到更灵活的执行策略时,应考虑使用Executor代替Thread

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值