线程数组对比Executor Service:为何前者执行速度远超后者?
为啥直接用线程数组比ExecutorService快这么多?
嘿,作为Java并发新手碰到这种巨大的耗时差异肯定会一脸懵,我来帮你拆解下最可能的原因,以及正确使用ExecutorService的姿势~
最可能的元凶:错误的ExecutorService调用方式
从你给出的耗时比例(3s vs 30s,正好和THREAD_COUNT=10的倍数一致)来看,大概率是你在使用ExecutorService的时候,每个任务提交后立刻调用了Future.get(),导致任务从并行变成了串行执行。
举个例子,你可能写出了这样的错误代码:
ExecutorService executor = Executors.newFixedThreadPool(THREAD_COUNT); for (int i = 0; i < THREAD_COUNT; i++) { Future<?> future = executor.submit(() -> { // 你的任务逻辑,比如单次耗时3s的操作 }); future.get(); // 这里会阻塞主线程,必须等当前任务完成才会提交下一个 } executor.shutdown();
这种情况下,10个任务是一个接一个排队执行的,总耗时自然是单个任务的10倍(3s×10=30s)。
而你用线程数组的写法是真正的并行执行:
Thread[] threads = new Thread[THREAD_COUNT]; for (int i = 0; i < THREAD_COUNT; i++) { threads[i] = new Thread(() -> { // 同样的耗时3s的任务逻辑 }); threads[i].start(); // 立刻启动线程,所有任务同时运行 } // 统一等待所有线程完成 for (Thread t : threads) { t.join(); }
这里所有线程同时推进,总耗时就是单个任务的执行时间(约3s),自然比串行的ExecutorService写法快很多。
正确的ExecutorService使用姿势
要让ExecutorService和线程数组一样实现并行,应该先把所有任务都提交到线程池,再统一等待所有任务完成,而不是提交一个就等一个。修改后的代码可以这样写:
ExecutorService executor = Executors.newFixedThreadPool(THREAD_COUNT); List<Future<?>> futures = new ArrayList<>(); // 先批量提交所有任务,不阻塞 for (int i = 0; i < THREAD_COUNT; i++) { Future<?> future = executor.submit(() -> { // 你的任务逻辑 }); futures.add(future); } // 统一等待所有任务执行完毕 for (Future<?> future : futures) { try { future.get(); } catch (Exception e) { e.printStackTrace(); } } // 优雅关闭线程池 executor.shutdown(); executor.awaitTermination(1, TimeUnit.MINUTES);
调整后,ExecutorService的执行耗时应该和线程数组基本一致,甚至后续复用线程池时会因为线程复用更高效。
其他小概率因素
如果你的写法本身没问题,那还有一些影响微小的因素可能导致差异:
- 线程池初始化开销:第一次创建ExecutorService时,需要完成线程初始化、调度逻辑配置等操作,会有一点点额外开销,但绝不会达到10倍的差距。
- 调度策略差异:线程池的线程调度逻辑和直接创建线程略有不同,但对任务执行总耗时的影响几乎可以忽略。
总的来说,最可能的问题就是你不小心让ExecutorService的任务串行执行了,调整下提交和等待的顺序就能解决~
内容的提问来源于stack exchange,提问作者clhost
相关产品推荐
相关产品推荐

