You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于ExecutorService#submit的疑问:为何无法按顺序输出1到10?

为什么ExecutorService.submit执行后无法按顺序输出1到10?

嘿,这个问题我之前也踩过坑,咱们来一步步分析为什么实际输出和你的预期不一样:

核心原因

1. 线程任务的执行是无序的

你用的Executors.newCachedThreadPool()是一个可缓存的线程池,它会根据任务数量创建多个线程并行执行提交的Callable任务。这些任务的执行顺序完全由CPU调度决定,不是按你提交的先后顺序完成的。比如第3个提交的任务可能比第1个任务更早完成Thread.sleep(20)和自增操作。

2. 共享的AtomicInteger导致返回值不是任务专属的结果

你所有的Callable都返回同一个全局的AtomicInteger对象ai。当某个任务执行完ai.incrementAndGet()后,还没来得及返回结果,其他任务可能已经对ai进行了多次自增。比如任务1刚把ai从0变成1,还没返回,任务2、3已经把ai变成3了,这时候任务1返回的ai的当前值就是3,而不是你期望的1。

3. 提前关闭线程池的小问题

你在遍历Future列表的finally块里调用了es.shutdown(),这会导致第一次循环时就关闭了线程池,后续的任务可能会被中断或者无法正常执行,不过这不是导致顺序问题的核心原因,但也是需要修正的点。

解决办法

如果你希望控制台按顺序输出1 2 3 ... 10,可以根据你的需求选择以下方案:

方案1:让任务串行执行(简单但失去并行优势)

把线程池换成单线程的Executors.newSingleThreadExecutor(),这样任务会按提交顺序依次执行,每个任务自增后返回的就是当前的顺序值:

ExecutorService es = Executors.newSingleThreadExecutor();

方案2:让每个任务返回自己的自增结果(保留并行,收集后可排序)

修改Callable,让它返回自增后的具体数值,而不是共享的AtomicInteger对象,这样每个任务的结果都是自己操作后的那个值。如果需要按顺序输出,可以收集所有结果后排序:

list.add(es.submit(new Callable<Integer>() {
    @Override
    public Integer call() throws Exception {
        try {
            Thread.sleep(20);
            return ai.incrementAndGet(); // 返回自增后的具体数值
        } catch (InterruptedException e) {
            e.printStackTrace();
            return -1;
        }
    }
}));
// 收集结果后排序输出
List<Integer> results = new ArrayList<>();
for (Future<Integer> future : list) {
    results.add(future.get());
}
Collections.sort(results);
results.forEach(System.out::println);

方案3:使用CountDownLatch等待所有任务完成,输出最终值(如果只需要最终结果)

如果你的需求只是确认最终ai的值是10,可以用CountDownLatch等待所有任务完成后再输出:

private static final int ii = 10;
public static AtomicInteger ai = new AtomicInteger();
public static CountDownLatch latch = new CountDownLatch(ii);

public static void main(String[] args) throws InterruptedException {
    ExecutorService es = Executors.newCachedThreadPool();
    for (int i = 0; i < ii; i++) {
        es.submit(new Callable<Void>() {
            @Override
            public Void call() throws Exception {
                try {
                    Thread.sleep(20);
                    ai.incrementAndGet();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    latch.countDown();
                }
                return null;
            }
        });
    }
    latch.await(); // 等待所有任务完成
    System.out.println(ai.get()); // 输出10
    es.shutdown();
}

内容的提问来源于stack exchange,提问作者Nugats

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:50:02