• 线程池之ThreadPoolExecutor使用(2)


    一 几个常见的对比

    1 Runnable vs Callable

    Runnable自 Java 1.0 以来一直存在,但Callable仅在 Java 1.5 中引入,目的就是为了来处理Runnable不支持的用例。

    Runnable 接口不会返回结果或抛出检查异常,但是**Callable 接口**可以。

    所以,如果任务不需要返回结果或抛出异常推荐使用 Runnable 接口,这样代码看起来会更加简洁。

    工具类 Executors 可以实现 Runnable 对象和 Callable 对象之间的相互转换。(Executors.callable(Runnable task)或 Executors.callable(Runnable task,Object resule))。

    Runnable.java

    @FunctionalInterface
    public interface Runnable {
       /**
        * 被线程执行,没有返回值也无法抛出异常
        */
        public abstract void run();
    }

    Callable.java

    @FunctionalInterface
    public interface Callable<V> {
        /**
         * 计算结果,或在无法这样做时抛出异常。
         * @return 计算得出的结果
         * @throws 如果无法计算结果,则抛出异常
         */
        V call() throws Exception;
    }

    execute() vs submit()

    1. execute()方法用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功与否
    2. submit()方法用于提交需要返回值的任务。线程池会返回一个 Future 类型的对象,通过这个 Future 对象可以判断任务是否执行成功 ,并且可以通过 Future 的 get()方法来获取返回值,get()方法会阻塞当前线程直到任务完成,而使用 get(long timeout,TimeUnit unit)方法则会阻塞当前线程一段时间后立即返回,这时候有可能任务没有执行完。

    我们以 AbstractExecutorService 接口中的一个 submit() 方法为例子来看看源代码:

        public Future<?> submit(Runnable task) {
            if (task == null) throw new NullPointerException();
            RunnableFuture<Void> ftask = newTaskFor(task, null);
            execute(ftask);
            return ftask;
        }

    上面方法调用的 newTaskFor 方法返回了一个 FutureTask 对象。

        protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
            return new FutureTask<T>(runnable, value);
        }

    我们再来看看execute()方法:

        public void execute(Runnable command) {
          ...
        }

    shutdown()VSshutdownNow()

    • shutdown() :关闭线程池,线程池的状态变为 SHUTDOWN。线程池不再接受新任务了,但是队列里的任务得执行完毕。
    • shutdownNow() :关闭线程池,线程的状态变为 STOP。线程池会终止当前正在运行的任务,并停止处理排队的任务并返回正在等待执行的 List。

    isTerminated() VS isShutdown()

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

    二.Callable+ThreadPoolExecutor示例代码

    MyCallable.java

    import java.util.concurrent.Callable;
    
    public class MyCallable implements Callable<String> {
        @Override
        public String call() throws Exception {
            Thread.sleep(1000);
            //返回执行当前 Callable 的线程名字
            return Thread.currentThread().getName();
        }
    }

    CallableDemo.java

    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;
    import java.util.concurrent.ArrayBlockingQueue;
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.Future;
    import java.util.concurrent.ThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;
    
    public class CallableDemo {
    
        private static final int CORE_POOL_SIZE = 5;
        private static final int MAX_POOL_SIZE = 10;
        private static final int QUEUE_CAPACITY = 100;
        private static final Long KEEP_ALIVE_TIME = 1L;
    
        public static void main(String[] args) {
    
            //使用阿里巴巴推荐的创建线程池的方式
            //通过ThreadPoolExecutor构造函数自定义参数创建
            ThreadPoolExecutor executor = new ThreadPoolExecutor(
                    CORE_POOL_SIZE,
                    MAX_POOL_SIZE,
                    KEEP_ALIVE_TIME,
                    TimeUnit.SECONDS,
                    new ArrayBlockingQueue<>(QUEUE_CAPACITY),
                    new ThreadPoolExecutor.CallerRunsPolicy());
    
            List<Future<String>> futureList = new ArrayList<>();
            Callable<String> callable = new MyCallable();
            for (int i = 0; i < 10; i++) {
                //提交任务到线程池
                Future<String> future = executor.submit(callable);
                //将返回值 future 添加到 list,我们可以通过 future 获得 执行 Callable 得到的返回值
                futureList.add(future);
            }
            for (Future<String> fut : futureList) {
                try {
                    System.out.println(new Date() + "::" + fut.get());
                } catch (InterruptedException | ExecutionException e) {
                    e.printStackTrace();
                }
            }
            //关闭线程池
            executor.shutdown();
        }
    }

    Output:

    Wed Nov 13 13:40:41 CST 2019::pool-1-thread-1
    Wed Nov 13 13:40:42 CST 2019::pool-1-thread-2
    Wed Nov 13 13:40:42 CST 2019::pool-1-thread-3
    Wed Nov 13 13:40:42 CST 2019::pool-1-thread-4
    Wed Nov 13 13:40:42 CST 2019::pool-1-thread-5
    Wed Nov 13 13:40:42 CST 2019::pool-1-thread-3
    Wed Nov 13 13:40:43 CST 2019::pool-1-thread-2
    Wed Nov 13 13:40:43 CST 2019::pool-1-thread-1
    Wed Nov 13 13:40:43 CST 2019::pool-1-thread-4
    Wed Nov 13 13:40:43 CST 2019::pool-1-thread-5
  • 相关阅读:
    LeetCode 123 Best Time to Buy and Sell Stock III
    直接选择排序算法汇总
    zoom:1是什么意思
    怎么去掉织梦网站首页带的index.html/index.php
    wamp apache无法启动的解决方法
    提交到svn服务器时,一直缓冲不,
    桌面上图标都不见了怎么办听语音
    如何清除网上浏览痕迹?清除缓存
    TortoiseSVN文件夹及文件图标不显示解决方法
    快捷键
  • 原文地址:https://www.cnblogs.com/Vincent-yuan/p/15042363.html
Copyright © 2020-2023  润新知