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

Java并发编程:List<Future<Integer>>的set方法参数不匹配问题

问题分析与解决

核心错误原因

你遇到的set(int, Future<Integer>) is not applicable to arguments (int,int)错误,本质是类型不匹配:

  • elements是List<Future<Integer>>类型,set方法要求第二个参数必须是Future<Integer>对象
  • 你传入的elements.get(firstIndex).get() - randomAmount是int类型,自然无法匹配

更关键的是:用Future<Integer>存储可修改的账户余额是完全错误的设计。Future的作用是获取异步任务的执行结果,一旦任务完成,其结果就固定了,不能被修改,也不适合作为并发场景下的状态存储容器。

正确解决方案

改用线程安全的数值类型AtomicInteger来存储账户余额,它专门用于并发场景下的原子性数值更新,同时修正代码中的其他问题:

修改后的完整代码

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class TransferDemo {
    public static void main(String[] args) throws InterruptedException {
        // 创建10线程的线程池
        var ex = Executors.newFixedThreadPool(10);

        // 初始化100个账户,每个初始余额1000,用AtomicInteger保证线程安全
        List<AtomicInteger> accounts = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            accounts.add(new AtomicInteger(1000));
        }

        // 计算初始总和
        int initialSum = accounts.stream().mapToInt(AtomicInteger::get).sum();
        System.out.println("Initial sum: " + initialSum);

        // 提交10000次转账任务
        for (int i = 0; i < 10_000; i++) {
            ex.submit(() -> {
                int fromIndex = ThreadLocalRandom.current().nextInt(100);
                int toIndex = ThreadLocalRandom.current().nextInt(100);
                // 避免自己转给自己
                if (fromIndex == toIndex) return;
                
                int amount = ThreadLocalRandom.current().nextInt(1000);
                AtomicInteger fromAccount = accounts.get(fromIndex);
                
                // 原子性地完成余额扣除:循环确保操作成功(避免竞态条件)
                while (true) {
                    int currentBalance = fromAccount.get();
                    if (currentBalance <= amount) {
                        // 余额不足,终止操作
                        break;
                    }
                    // 尝试原子更新:如果当前余额还是currentBalance,就减去amount
                    if (fromAccount.compareAndSet(currentBalance, currentBalance - amount)) {
                        // 扣除成功后,给目标账户增加对应金额
                        accounts.get(toIndex).addAndGet(amount);
                        break;
                    }
                }
            });
        }

        // 关闭线程池,不再接受新任务,等待所有任务完成
        ex.shutdown();
        ex.awaitTermination(1, TimeUnit.MINUTES);

        // 计算最终总和,验证转账过程中总额不变
        int finalSum = accounts.stream().mapToInt(AtomicInteger::get).sum();
        System.out.println("Final sum: " + finalSum);
    }
}

关键修改点说明

  1. 替换存储容器:用List<AtomicInteger>替代List<Future<Integer>>,AtomicInteger支持原子性的读写和更新,完美适配并发场景下的余额修改需求。
  2. 修正线程池生命周期:原代码中提前调用ex.shutdown(),导致后续submit任务时会抛出RejectedExecutionException,现在改为所有任务提交完成后再关闭线程池,并等待任务执行完毕。
  3. 完整转账逻辑:原代码只实现了扣款,没有给目标账户加钱,现在补充了accounts.get(toIndex).addAndGet(amount)的逻辑。
  4. 原子性更新:用compareAndSet循环实现原子性扣款,避免多个线程同时修改同一账户时出现竞态条件(比如余额判断后被其他线程修改,导致超额扣款)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 16:05:34