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

