Java中实现任一FutureTask完成后终止另一任务的方法
解决方案
首先要注意:你当前使用的Executors.newSingleThreadExecutor()是单线程执行器,两个任务会串行执行,根本无法实现并行。第一步必须换成多线程线程池,比如Executors.newFixedThreadPool(2)。
要实现「一个任务完成就终止另一个」的逻辑,核心思路是:
- 当任意一个任务执行完成时,立即调用另一个任务对应的
Future.cancel(true)方法,向目标线程发送中断信号 - 在
method1()和method2()内部,定期检查当前线程的中断状态,一旦检测到中断,就停止执行并返回
修改后的完整代码
import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicReference; public class Main { public static void main(String[] args) { try { // 换成多线程线程池,保证两个任务并行执行 ExecutorService executor = Executors.newFixedThreadPool(2); // 用AtomicReference来保存两个Future,方便任务间互相访问 AtomicReference<Future<Response>> future1Ref = new AtomicReference<>(); AtomicReference<Future<Response>> future2Ref = new AtomicReference<>(); // 任务1 Callable<Response> task1 = () -> { Response response = method1(); // 任务1完成后,立即取消任务2 if (future2Ref.get() != null) { future2Ref.get().cancel(true); } return response; }; // 任务2 Callable<Response> task2 = () -> { Response response = method2(); // 任务2完成后,立即取消任务1 if (future1Ref.get() != null) { future1Ref.get().cancel(true); } return response; }; // 提交任务并保存Future引用 future1Ref.set(executor.submit(task1)); future2Ref.set(executor.submit(task2)); try { // 获取结果,任务被取消时会抛出CancellationException Response response1 = future1Ref.get().get(); System.out.println("任务1完成,结果:" + response1.getMsg()); } catch (CancellationException e) { System.out.println("任务1被取消"); } try { Response response2 = future2Ref.get().get(); System.out.println("任务2完成,结果:" + response2.getMsg()); } catch (CancellationException e) { System.out.println("任务2被取消"); } executor.shutdownNow(); // 关闭线程池 } catch (Exception ex) { ex.printStackTrace(); } } private static Response method1() { Response response = new Response(); response.setMsg("test1"); // 模拟耗时操作,期间定期检查中断状态 try { for (int i = 0; i < 10; i++) { // 检查是否被中断,如果是则立即停止执行 if (Thread.currentThread().isInterrupted()) { System.out.println("method1检测到中断,提前返回"); return null; } Thread.sleep(500); // 模拟耗时步骤 } } catch (InterruptedException e) { // 捕获中断异常,重置中断状态并返回 Thread.currentThread().interrupt(); System.out.println("method1被中断"); return null; } return response; } private static Response method2() { Response response = new Response(); response.setMsg("test2"); // 模拟耗时操作,期间定期检查中断状态 try { for (int i = 0; i < 5; i++) { if (Thread.currentThread().isInterrupted()) { System.out.println("method2检测到中断,提前返回"); return null; } Thread.sleep(500); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); System.out.println("method2被中断"); return null; } return response; } } class Response { String msg; public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
关键逻辑说明
- 线程池修正:使用
newFixedThreadPool(2)保证两个任务能并行执行,这是实现需求的前提。 - 任务间的取消触发:每个任务执行完成后,通过
AtomicReference获取另一个任务的Future,调用cancel(true)发送中断信号。 - method内部的中断检查:
- 在耗时操作的循环中,定期调用
Thread.currentThread().isInterrupted()检查中断状态,若已中断则提前返回。 - 捕获
InterruptedException(比如Thread.sleep()被中断时抛出),重置中断状态后返回,避免中断状态被吞噬。
- 在耗时操作的循环中,定期调用
注意事项
Future.cancel(true)只能向线程发送中断信号,无法强制终止线程,所以任务内部必须配合检查中断状态才能实现真正的终止。- 如果你的耗时操作是阻塞在某个IO调用上,需要确保该IO操作能响应中断(比如使用NIO而非传统阻塞IO),否则中断信号无法生效。
内容的提问来源于stack exchange,提问作者user_apr
相关产品推荐
相关产品推荐

