zoukankan      html  css  js  c++  java
  • Executor(一)ExecutorService 线程池

    Executor(一)ExecutorService 线程池

    本篇主要涉及到的是 java.util.concurrent 包中的 ExecutorService。ExecutorService 就是 Java 中对线程池的实现。

    一、ExecutorService 介绍

    Java API 对 ExecutorService 接口的实现有两个,它们是 Java 线程池具体实现类

    1. ThreadPoolExecutor
    2. ScheduledThreadPoolExecutor

    Executor 类图

    二、ExecutorService 创建

    创建一个什么样的 ExecutorService 的实例(即线程池)需要根据具体应用场景而定,不过 Java 给我们提供了一个 Executors 工厂类,它可以帮助我们很方便的创建各种类型 ExecutorService 线程池,Executors 一共可以创建下面这四类线程池:

    1. newCachedThreadPool 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
    2. newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
    3. newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
    4. newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO)

    备注:Executors 只是一个工厂类,它所有的方法返回的都是 ThreadPoolExecutor、ScheduledThreadPoolExecutor 这两个类的实例。

    三、ExecutorService 使用

    public interface ExecutorService extends Executor {
        <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;
    
        void shutdown();
        List<Runnable> shutdownNow();
        boolean isShutdown();
        boolean isTerminated();
        boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;
    
    }
    
    public interface Executor {
    
        void execute(Runnable command);
    }
    

    3.1 execute(Runnable task)

    ExecutorService executorService = Executors.newSingleThreadExecutor();
    
    executorService.execute(() -> {
        System.out.println("Asynchronous task");
    });
    
    executorService.shutdown();
    

    这个方法有个问题,就是没有办法获知 task 的执行结果。如果我们想获得 task 的执行结果,我们可以传入一个 Callable 的实例(下面会介绍)。

    3.2 submit(Runnable task)

    submit(Runnable) 和 execute(Runnable) 区别是前者可以返回一个 Future 对象,通过返回的 Future 对象,我们可以检查提交的任务是否执行完毕,请看下面执行的例子:

    Future future = executorService.submit(() -> {
        System.out.println("Asynchronous task");
    });
    
    future.get();  //returns null if the task has finished correctly.
    

    如果任务执行完成,future.get() 方法会返回一个 null。注意,future.get()方法会产生阻塞。

    3.3 submit(Callable task)

    submit(Callable) 和 submit(Runnable) 类似,也会返回一个 Future 对象,但是除此之外,submit(Callable) 接收的是一个 Callable 的实现,Callable 接口中的 call() 方法有一个返回值,可以返回任务的执行结果,而 Runnable 接口中的 run() 方法是 void 的,没有返回值。请看下面实例:

    Future<?> future = executorService.submit(() -> {
        System.out.println("Asynchronous task");
        return "binarylei";
    });
    
    System.out.println("future.get() = " + future.get());
    

    如果任务执行完成,future.get() 方法会返回 Callable 任务的执行结果。注意,future.get() 方法会产生阻塞。

    3.4 invokeAny(Collection tasks)

    invokeAny(...) 方法接收的是一个 Callable 的集合,执行这个方法不会返回 Future,但是会返回所有 Callable 任务中其中一个任务的执行结果。这个方法也无法保证返回的是哪个任务的执行结果,反正是其中的某一个。请看下面实例:

    Set<Callable<String>> tasks = new HashSet<>();
    for (int i = 0; i < 5; i++) {
        int num = i;
        tasks.add(new Callable<String>() {
            @Override
            public String call() throws Exception {
                return String.valueOf(num);
            }
        });
    }
    System.out.println(executorService.invokeAny(tasks));
    

    大家可以尝试执行上面代码,每次执行都会返回一个结果,并且返回的结果是变化的,可能会返回“Task2”也可是“Task1”或者其它。

    3.5 invokeAll(Collection tasks)

    invokeAll(...) 与 invokeAny(...) 类似也是接收一个 Callable 集合,但是前者执行之后会返回一个 Future 的 List,其中对应着每个 Callable 任务执行后的 Future 对象。情况下面这个实例:

    Set<Callable<String>> tasks = new HashSet<>();
    for (int i = 0; i < 5; i++) {
        int num = i;
        tasks.add(new Callable<String>() {
            @Override
            public String call() throws Exception {
                return String.format("Task-%s", num);
            }
        });
    }
    
    List<Future<String>> futures = executorService.invokeAll(tasks);
    for (int i = 0; i < futures.size(); i++) {
        System.out.println(futures.get(i).get());
    }
    

    四、ExecutorService 关闭

    当我们使用完成 ExecutorService 之后应该关闭它,否则它里面的线程会一直处于运行状态。

    举个例子,如果的应用程序是通过 main() 方法启动的,在这个 main() 退出之后,如果应用程序中的 ExecutorService 没有关闭,这个应用将一直运行。之所以会出现这种情况,是因为 ExecutorService 中运行的线程会阻止 JVM 关闭。

    1. shutdown() :在调用 shutdown() 方法之后,ExecutorService 不会立即关闭,但是它不再接收新的任务,直到当前所有线程执行完成才会关闭,所有在 shutdown() 执行之前提交的任务都会被执行。

    2. shutdownNow() :立即关闭 ExecutorService,这个动作将跳过所有正在执行的任务和被提交还没有执行的任务。但是它并不对正在执行的任务做任何保证,有可能它们都会停止,也有可能执行完成。

    3. isShutdown():当调用 shutdown() 方法后返回为 true。

    4. isTerminated():当调用 shutdown() 方法后,并且所有提交的任务完成后返回为 true。

    5. awaitTermination(2, TimeUnit.SECONDS):当调用 shutdown() 方法后,2s 内执行完所有的任务返回 true,超时返回 false。

    //1. ExecutorService 不会立即关闭,直到所有线程执行完成才会关闭,所有在shutdown()执行之前提交的任务都会被执行。
    executorService.shutdown();
    
    //2. 关闭ExecutorService,并不对正在执行的任务做任何保证,有可能它们都会停止,也有可能执行完成。
    //executorService.shutdownNow();
    
    //3. 当调用shutdown()方法后返回为true
    System.out.println(executorService.isShutdown());
    
    //4. 当调用shutdown()方法后,并且所有提交的任务完成后返回为true
    System.out.println(executorService.isTerminated());
    
    //5. 2s 内执行守任务则返回true,否则超时返回false 
    System.out.println(executorService.awaitTermination(2, TimeUnit.SECONDS));
    
    //6. 执行完所有任务后退出
    /*while (!executorService.isTerminated()) {
        System.out.println("正在执行任务");
    }*/
    System.out.println(executorService.isTerminated());
    

    每天用心记录一点点。内容也许不重要,但习惯很重要!

  • 相关阅读:
    easyExcel入门
    UML-从需求到设计--迭代进化
    UML-操作契约总结
    102. Binary Tree Level Order Traversal
    98. Validate Binary Search Tree
    95. Unique Binary Search Trees II
    96. Unique Binary Search Trees
    94. Binary Tree Inorder Traversal
    84. Largest Rectangle in Histogram
    92. Reverse Linked List II
  • 原文地址:https://www.cnblogs.com/binarylei/p/10024259.html
Copyright © 2011-2022 走看看