zoukankan      html  css  js  c++  java
  • 聊聊高并发(三十八)解析java.util.concurrent各个组件(十四) 理解Executor接口的设计

    JUC包中除了一系列的同步类之外,就是Executor运行框架相关的类。对于一个运行框架来说,能够分为两部分

    1. 任务的提交

    2. 任务的运行。

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


    Executor接口设计的目的是专注于任务的运行。和任务的提交解耦。

    任务的提交由任务的创建者处理。

    Executor接口封装了任务运行的细节,比方怎样使用线程,是否定时运行等等。

    Executor接口非常easy,就一个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);
          }
        }
      }}


  • 相关阅读:
    LeetCode_441. Arranging Coins
    LeetCode_437. Path Sum III
    Spearman秩相关系数和Pearson皮尔森相关系数
    Spark MLlib 之 Basic Statistics
    Spark MLlib 之 Naive Bayes
    Spark MLlib Data Type
    maven 下载 源码和javadoc 命令
    Hadoop的数据输入的源码解析
    Spark相关错误汇总
    Spark External Datasets
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/5082200.html
Copyright © 2011-2022 走看看