ExecutorCompletionService测试

ExecutorCompletionService(以下简称ECS)是java.util.concurrent工具类,用来代理ExecutorService,以木桶效应。
本人测试在最差情况下

  • 没用ECS的异步
  • 用了ECS的异步
  • 传统同步
import java.util.concurrent.*;
import java.time.*;
import java.util.*;
// import java.util.logging.*;
import java.util.function.*;
import java.io.*;
import java.text.*;

public class Main {

    private static final Logger logger = Logger.getLogger();
    
    public static void main(String[] args) throws Throwable {
        
        ExecutorService es = Executors.newVirtualThreadPerTaskExecutor();j a
        // 创建延时任务(返回值,耗时)
        var tasks = List.of(delayed("最慢完成的", 5),
                            delayed("一般", 3),
                            delayed("最快完成的", 1));

        final Logger logger = new Logger();

        tryExpAsync(es, tasks, true,  logger::info); // 没用
        tryExpAsync(es, tasks, false, logger::info); // 用了
        tryExp(tasks, logger::info); // 同步
    
        es.close();
    }

    /**
     * 自定义日志工具类。
     *
     * 这个日志工具类会输出当前时间,精细到秒数
     * 用法:
     * <pre>
     *   final Logger logger = Logger.getLogger();
     *   logger.info("Hello, world!");
     * </pre>
     */
    private static class Logger {
        static final SimpleDateFormat sdf = new SimpleDateFormat("HH-mm-ss");
        static Logger theLogger;
        private Logger() {}
        public static Logger getLogger() {
            if (theLogger == null) {
                synchronized (Logger.class) {
                    if (theLogger == null) {
                        theLogger = new Logger();
                    }
                }
            }
            return theLogger;
        }
        public void info(String msg) {
            System.out.println("[%s] %s".formatted(sdf.format(new Date()), msg));
        }
    }

    // 计时
    private static <V> void tryExpAsync(ExecutorService es,
                                        List<Callable<V>> tasks,
                                        boolean orderedExecution,
                                        Consumer<V> action)
    throws Exception {
        logger.info("开始任务!!!");
        var now = Instant.now(); // 开始计时
        resolveAll(es, tasks, orderedExecution, action);
        System.out.println(now.elapsed().toSeconds() + "秒");
    }

    private static <V> void tryExp(List<Callable<V>> tasks, Consumer<V> action)
        throws Exception {
        logger.info("开始同步任务");
        var now = Instant.now();
        
        for (Callable<V> task : tasks) {
            V result = task.call();
            if (result != null)
                action.accept(result);
        }
        System.out.println(now.elapsed().toSeconds() + " 秒");
    }

    /**
     *
     * @param e 线程池
     * @param tasks 要被线程池执行的任务集
     * @param orderedExecution 如果为 {@code true},就会禁用 {@code ExecutorCompletionService}
     *                         这就意味着线程池的结果是按照
     * @param action 传入一个消费器,用来操作线程池完成任务后的结果
     */
    private static <V> void resolveAll(ExecutorService e,
                                       Collection<Callable<V>> tasks,
                                       boolean orderedExecution,
                                       Consumer<V> action)
    throws Exception
    {    
        final int len = tasks.size();
        
        if (orderedExecution) {
            // 将所有的任务提交到线程池,然后返回其Futures
            List<Future<V>> futures = tasks.stream().map(e::submit).toList();
            for (int i = 0, n = len; i < len; ++i) // 这里不用加强for遍历,以提高性能
                action.accept(futures.get(i).get()); // 返回 Future
        } else {
            var ecs = new ExecutorCompletionService<V>(e);
            tasks.forEach(ecs::submit);
            for (int i = len; i > 0; --i)
                action.accept(ecs.take().get());
        }
    }

    /**
     * 创建一个延时任务,返回一个 Callable<V>
     *
     * @param result 要返回的结果
     * @param timeout 延时返回 {@code result} 的时长
     */
    private static <V> Callable<V> delayed(V result, long timeout) {
        return (Callable<V>)
            () -> { TimeUnit.SECONDS.sleep(timeout); return result; };
    }

    /**
     * 计时工具类,用法如下:
     * <pre>
     *   var now = Instant.now();
     *   // 耗时任务
     *   System.out.println(now.elapsed().toSeconds());
     * </pre>
     */
    private static class Instant {
        Duration dur;
        Instant(Duration durr) { dur = durr; }
        Instant(long timeout) { this(Duration.ofMillis(timeout)); }
        static Instant now() {
            return new Instant(
                Duration.ofMillis(System.currentTimeMillis()));
        }
        Instant elapsed() {
            return new Instant(
                Duration.ofMillis(System.currentTimeMillis() - dur.toMillis()));
        }
        long toSeconds() { return dur.toSeconds(); }
        long toMillis()  { return dur.toMillis(); }
        long toHours()   { return dur.toHours(); }
        long toDays()    { return dur.toDays(); }
    }
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值