您的位置:首页 > 编程语言 > Java开发

聊聊高并发(三十八)解析java.util.concurrent各个组件(十四) 理解Executor接口的设计

2015-06-25 17:33 896 查看
JUC包中除了一系列的同步类之外,就是Executor执行框架相关的类。对于一个执行框架来说,可以分为两部分

1. 任务的提交

2. 任务的执行。

这是一个生产者消费者模式,提交任务的操作是生产者,执行任务的线程相当于消费者。

Executor接口设计的目的是专注于任务的执行,和任务的提交解耦。任务的提交由任务的创建者处理。Executor接口封装了任务执行的细节,比如如何使用线程,是否定时执行等等。Executor接口很简单,就一个execute方法。

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


如果不使用Executor接口,直接用Thread显式地来执行一个Runnable,代码是这样的

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


而使用Executor接口执行Runnable的代码是这样的

Executor executor = xxxExecutor;
executor.execute(new RunnableTask());


可以看到Executor接口的一个是屏蔽了任务执行的细节。它完全可以直接使用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();
     }
}


《Java并发编程实战》一书中将任务执行的细节称为执行策略。执行策略定义了任务执行的What, Where, When, How

1. 在什么(What)线程中执行任务?

2. 任务按照什么(What)顺序执行(FIFO,LIFO,优先级)

3. 有多少个(How Many)任务能并发执行

4. 在队列中有(How Many)任务在等待执行

5. 如果系统由于过载Overload而需要拒绝一个任务,那么应该选择哪一个(Which)任务?如何(How)通知应用程序有任务被拒绝

6. 在执行一个任务之前或之后,应该进行哪些(What)动作?

这几点都是设计一个执行框架需要考虑的事情。比如ThreadPoolExecutor解决了线程池的问题,ExecutorService解决了执行任务生命周期管理的问题,ScheduleExecutorService解决了定时执行任务的问题。

下面这个在Executor JavaDoc里的串行执行任务的Exector,可以看到如何扩展Executor来自定义执行的策略。

1. 封装了一个ArrayDeque队列来存放待执行的Runnable任务

2. 真正用来执行任务的Executor对象

3. 当前要执行的任务active对象

4. SerialExecutor的execute方法先讲传入的Runnable任务再封装一层,加入到tasks队列,保证这个任务执行完后会去调用scheduleNext()执行下一个任务。然后判断active对象是否是null,表示是第一次执行,就显式地执行scheduleNext().

5. scheduleNext()方法从队列中取任务执行

6. execute()和scheduleNext()都是synchronized方法,保证串行执行。

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() {
        public void run() {
          try {
            r.run();
          } finally {
            scheduleNext();
          }
        }
      });
      if (active == null) {
        scheduleNext();
      }
    }
 
    protected synchronized void scheduleNext() {
      if ((active = tasks.poll()) != null) {
        executor.execute(active);
      }
    }
  }}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: