futuretask线程安全,允许多线程并发调用get()获取同一结果且任务只执行一次;其通过状态机和cas保证状态变更原子性,未完成时阻塞等待,完成后立即返回;需避免重复提交或手动多次run()。

可以,FutureTask 本身是线程安全的,允许多个线程同时调用 get() 等待同一个结果,且只会执行一次计算任务。
FutureTask 的线程安全机制
FutureTask 内部使用了状态机(如 NEW、COMPLETING、NORMAL、EXCEPTIONAL 等)和 CAS 操作来保证状态变更的原子性。当第一个线程调用 run() 触发任务执行后,后续调用 run() 会被忽略;多个线程并发调用 get() 时,未完成的线程会阻塞在内部的等待队列中,任务完成后统一唤醒并返回相同结果。
多个线程调用 get() 的行为
- 所有线程看到的是同一份结果(成功值或异常),不会重复执行任务逻辑
- 若任务尚未完成,
get()会阻塞,直到任务结束(或超时/被中断) - 若任务已结束(无论成功或失败),后续
get()立即返回结果,不阻塞 - 即使一个线程在
get()中被中断,不影响其他线程正常获取结果
使用注意事项
虽然 FutureTask 支持多线程共享,但需注意以下几点:
- 确保只调用一次
execute()或submit()提交任务,避免重复提交导致不可预期行为 - 不要手动调用
run()多次 —— FutureTask 的run()是幂等的,但业务逻辑可能不是,应由执行器统一调度 - 若需多次获取结果,可直接复用同一个 FutureTask 实例,无需创建多个
- 注意内存可见性:FutureTask 内部已通过 volatile 和锁机制保证结果对所有线程可见,无需额外同步
简单示例
以下代码演示两个线程等待同一个 FutureTask 结果:
FutureTask<string> task = new FutureTask(() -> {
Thread.sleep(1000);
return "done";
});
new Thread(task).start(); // 启动任务
// 两个线程同时 get
new Thread(() -> {
try { System.out.println("T1: " + task.get()); }
catch (Exception e) { e.printStackTrace(); }
}).start();
new Thread(() -> {
try { System.out.println("T2: " + task.get()); }
catch (Exception e) { e.printStackTrace(); }
}).start();
</string>
输出中 T1 和 T2 都会打印 "done",且 T2 不会触发第二次计算。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











