zoukankan      html  css  js  c++  java
  • Executor框架(转)

    摘要:

           Executor作为灵活且强大的异步执行框架,其支持多种不同类型的任务执行策略,提供了一种标准的方法将任务的提交过程和执行过程解耦开发,基于生产者-消费者模式,其提交任务的线程相当于生产者,执行任务的线程相当于消费者,并用Runnable来表示任务,Executor的实现还提供了对生命周期的支持,以及统计信息收集,应用程序管理机制和性能监视等机制。
     
    一、Exexctor简介
     Executor的UML图:(常用的几个接口和子类)
                              

     Executor:一个接口,其定义了一个接收Runnable对象的方法executor,其方法签名为executor(Runnable command),

     
    ExecutorService:是一个比Executor使用更广泛的子类接口,其提供了生命周期管理的方法,以及可跟踪一个或多个异步任务执行状况返回Future的方法
     
    AbstractExecutorService:ExecutorService执行方法的默认实现
     
    ScheduledExecutorService:一个可定时调度任务的接口
     
    ScheduledThreadPoolExecutor:ScheduledExecutorService的实现,一个可定时调度任务的线程池
     
    ThreadPoolExecutor:线程池,可以通过调用Executors以下静态工厂方法来创建线程池并返回一个ExecutorService对象:
     

    二、Executor框架的两级调度模型

      在HotSpot VM的线程模型中,JAVA线程被一对一映射为本地操作系统线程。JAVA线程启动时会启动一个本地操作系统线程:当该JAVA线程终止时,这个操作系统线程也会被回收。操作系统会调度所有线程并将它们分配给可用的CPU。
     
     两级调度模型的示意图:
                      

      从图中可以看出,该框架用来控制应用程序的上层调度(下层调度由操作系统内核控制,不受应用程序的控制)。

     

    三、Executor框架的结构

     Executor主要由三部分组成:任务产生部分,任务处理部分,结果获取部分。(设计模式:生产者与消费者模式)

    先来看个图:

                      

    1.任务的产生:Runnable接口和Callable接口

      这2个对象属于任务对象。工具类Executors可以把一个Runnable对象封装为Callable对象。当我们拥有任务对象之后,就可以将其交给ExecutorService(Executor的一个实现接口)了,这样转入第二部分–任务处理部分。
     

    2.任务的处理:Executor接口—>ExecutorService接口 

      任务的处理主要是将任务丢到线程池中,由线程池提供线程将任务“消费掉”。

      线程池有2类:ThreadPoolExecutor和ScheduledThreadPoolExecutor。2种线程池类均可以通过工厂类Executors来创建。  

     ⑴:ThreadPoolExecutor类

      工厂类可以创建3种类型的ThreadPoolExecutor类:

        ①:FixedThreadPool:拥有固定数量线程的线程池,限制了线程的数目,适用于负载比较重的服务器。

        ②:SingleThreadPool:单个线程的线程池,适用于需要保证顺序的执行各个任务;任意时间点,不会有多个线程活动。

        ③:CachedThreadPool:大小无界的线程池,适用于执行很多的短期异步任务的小程序,或者是负载较轻的服务器。

     ⑵:ScheduleThreadPoolExecutor类
      工厂类可以创建2种类型的SchedulePoolExecutor类:

        ①:ScheduleThreadPoolExecutor:包含若干线程。

        ②:SingleThreadScheduleExecutor:单个线程。

    3.任务结果的获取:Future接口

      Future接口有个实现类FutureTask,迄今为止API中返回的都是FutureTask对象,未来的JDK实现中,可能有Future对象。
     

    四、Executors类

     Executors类,提供了一系列工厂方法用于创建线程池,返回的线程池都实现了ExecutorService接口。
                     

     例子:newCachedThreadPool

    /**
     * 运行结果:可以看出缓存线程池大小是不定值,可以需要创建不同数量的线程,
     * 在使用缓存型池时,先查看池中有没有以前创建的线程,如果有,就复用.如果没有,就新建新的线程加入池中,
     * 缓存型池子通常用于执行一些生存期很短的异步型任务
     *
     */
    public class newCachedThreadPoolTest {
        public static void main(String[] args) {
            //创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程
            ExecutorService executorService = Executors.newCachedThreadPool();
            
            for (int i = 0; i < 20; i++) {
                Runnable syncRunnable = new Runnable() {
                    @Override
                    public void run() {
                        System.out.println(Thread.currentThread().getName());
                    }
                };
                executorService.execute(syncRunnable);
            }
        }
    }

    console输出结果:

                 

    例子:newFixedThreadPool

    /**
     * 运行结果:总共只会创建5个线程, 开始执行五个线程,
     * 当五个线程都处于活动状态,再次提交的任务都会加入队列等到其他线程运行结束,当线程处于空闲状态时会被下一个任务复用
     *
     */
    public class newFixedThreadPoolTest {
        public static void main(String[] args) {
            //Executors工厂类创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程
            ExecutorService executorService = Executors.newFixedThreadPool(5);
            for(int i = 0; i < 20; i++) {
                Runnable synRunnable = new Runnable() {
                    public void run() {
                        System.out.println(Thread.currentThread().getName());
                    }
                };
                executorService.execute(synRunnable);
            }
        }
    }

    console输出结果:

              

    例子:newScheduledThreadPool

    public class newScheduledThreadPoolTest {
        public static void main(String[] args) {
            //创建一个定长线程池,支持定时及周期性任务执行
            ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5);
            for (int i = 0; i < 20; i++) {
                final int count = i;
                Runnable syncRunnable = new Runnable() {
                    @Override
                    public void run() {
                        System.out.println(Thread.currentThread().getName() + " ----- " + count);
                    }
                };
                //表示从提交任务开始计时,5000毫秒后执行
                //运行结果和newFixedThreadPool类似,不同的是newScheduledThreadPool是延时一定时间之后才执行
                executorService.schedule(syncRunnable, 5000, TimeUnit.MILLISECONDS);
            }
        }
    }

    console输出结果:

                   

    例子:newSingleThreadExecutor

    public class newSingleThreadExecutorTest {
        public static void main(String[] args) {
            //创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行
            //运行结果:只会创建一个线程,当上一个执行完之后才会执行第二个
            ExecutorService executorService = Executors.newSingleThreadExecutor();
            for (int i = 0; i < 20; i++) {
                Runnable syncRunnable = new Runnable() {
                    public void run() {
                        try {
                            Thread.sleep(2000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName());
                    }
                };
                executorService.execute(syncRunnable);
            }
        }
    }

    console输出结果:

                 

    结合Future接口来做一个实测

    public class FutureDemo {
    
        public static void main(String[] args) {
            ExecutorService pool = Executors.newFixedThreadPool(3);
    
            // CompletionService接口内部维护一个结果队列:一堆future....
            CompletionService<Integer> cs = new ExecutorCompletionService<>(pool);
    
            for (int i = 1; i < 11; i++) {
                final int flag = i * 10;
                cs.submit(new Callable<Integer>() {
    
                    @Override
                    public Integer call() throws Exception {
                        System.out.println(Thread.currentThread().getName());
                        Thread.sleep(1000);
                        return flag;
                    }
                });
            }
    
            for (int i = 0; i < 11; i++) {
                try {
                    System.out.println(cs.take().get());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
            }
    
            pool.shutdown();
        }
    }

    console输出结果:

                  

    附录一张图来介绍Executor框架

    资料出处:https://blog.csdn.net/qq_16811963/article/details/52161713

         https://blog.csdn.net/qq_35794278/article/details/81481483

     
     
  • 相关阅读:
    NYOJ--42--dfs水过||并查集+欧拉通路--一笔画问题
    万能头文件#include
    微信小程序一
    项目上线
    docker
    支付宝支付
    django的分类过滤,区间过滤
    drf分页组件,搜索组件,排序组件,自定义过滤组件
    celery异步执行任务框架
    git使用二
  • 原文地址:https://www.cnblogs.com/myseries/p/11436117.html
Copyright © 2011-2022 走看看