FutureTask深度解析

Java并发包(JUC)FutureTask深度解析

一、核心特性与定位

1.1 双重角色设计

FutureTask是Java并发包中实现RunnableFuture接口的核心类,同时扮演两种角色:

  1. Runnable实现:可被Executor线程池执行
  2. Future实现:提供任务结果获取和状态管理

类继承体系

RunnableFuture
FutureTask
Future
Runnable

1.2 核心特性矩阵

特性行为表现适用场景
状态机驱动NEW/COMPLETING/NORMAL/EXCEPTIONAL/CANCELLED任务生命周期管理
结果缓存计算结果仅保留一次重复获取结果场景
中断协作响应Thread.interrupt()需要可中断任务的场景
线程安全状态变更通过CAS保证多线程环境下的任务控制

二、核心机制解析

2.0. 类结构

public class FutureTask<V> implements RunnableFuture<V> {
    // 内部状态定义
    private volatile int state;
    private static final int NEW          = 0;
    private static final int COMPLETING   = 1;
    private static final int NORMAL       = 2;
    private static final int EXCEPTIONAL  = 3;
    private static final int CANCELLED    = 4;
    private static final int INTERRUPTING = 5;
    private static final int INTERRUPTED  = 6;

    // 任务结果或异常
    private Object outcome;

    // 调用者(执行任务的线程)
    private volatile Thread runner;

    // 等待线程队列(通过 AQS 实现)
    private volatile WaitNode waiters;

    // 构造器(封装 Callable)
    public FutureTask(Callable<V> callable) {
        this.callable = callable;
        this.state = NEW;
    }

    // 构造器(封装 Runnable 和结果)
    public FutureTask(Runnable runnable, V result) {
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;
    }

    // 核心方法:执行任务
    public void run() {
        if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex); // 设置异常
                }
                if (ran)
                    set(result); // 设置结果
            }
        } finally {
            runner = null;
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }

    // 核心方法:获取结果(阻塞)
    public V get() throws InterruptedException, ExecutionException {
        int s = state;
        if (s <= COMPLETING)
            s = awaitDone(false, 0L); // 等待完成
        return report(s);
    }

    // 核心方法:取消任务
    public boolean cancel(boolean mayInterruptIfRunning) {
        if (!(state == NEW && UNSAFE.compareAndSwapInt(this, stateOffset, NEW, mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
            return false;
        try {
            if (mayInterruptIfRunning) {
                Thread r = runner;
                if (r != null)
                    r.interrupt(); // 中断执行线程
            }
        } finally {
            finishCompletion(); // 唤醒等待线程
        }
        return true;
    }
}

2.0.1. 关键方法详解

  • run()

    • 执行任务逻辑,调用 Callable.call()
    • 通过 CAS 确保只有一个线程执行任务。
    • 任务完成后调用 set(result)setException(ex) 更新状态。
  • get()

    • 阻塞等待任务完成,通过 awaitDone 进入等待队列。
    • 任务完成后调用 report(s) 返回结果或异常。
  • set(result)

    • 通过 CAS 将状态从 COMPLETING 更新为 NORMAL
    • 唤醒所有等待线程(finishCompletion)。
  • setException(ex)

    • 将状态更新为 EXCEPTIONAL,并保存异常。
    • 唤醒所有等待线程。

2.1 状态转换图

run()执行
正常完成
抛出异常
cancel(true/false)
中断发生
NEW
COMPLETING
NORMAL
EXCEPTIONAL
CANCELLED

2.2 任务执行流程(源码解析)

// 简化版run()方法逻辑
public void run() {
    if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread()))
        return;
    try {
        Callable<V> c = callable;
        if (c != null && state == NEW) {
            V result;
            boolean ran;
            try {
                result = c.call(); // 执行实际任务
                ran = true;
            } catch (Throwable ex) {
                result = null;
                ran = false;
                setException(ex); // 设置异常状态
                return;
            }
            if (ran)
                set(result); // 设置正常结果
        }
    } finally {
        runner = null;
        int s = state;
        if (s >= INTERRUPTING)
            handlePossibleCancellationInterrupt(s);
    }
}

2.3 中断机制

协作式中断实现

protected void done() {
    if (interrupted) {
        Thread.currentThread().interrupt(); // 恢复中断状态
    }
}

public boolean cancel(boolean mayInterruptIfRunning) {
    if (!(state == NEW && UNSAFE.compareAndSwapInt(this, stateOffset, NEW, mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
        return false;
    try {
        if (mayInterruptIfRunning) {
            Thread r = runner;
            if (r != null)
                r.interrupt(); // 中断执行线程
        }
    } finally {
        finishCompletion();
    }
    return true;
}

三、典型使用场景

3.1 异步任务处理

基础使用模式

// 创建任务
FutureTask<Integer> futureTask = new FutureTask<>(() -> {
    Thread.sleep(2000);
    return 42;
});

// 提交执行
new Thread(futureTask).start();

// 获取结果(非阻塞)
try {
    Integer result = futureTask.get(); // 阻塞直到完成
    System.out.println("Result: " + result);
} catch (InterruptedException | ExecutionException e) {
    e.printStackTrace();
}

3.2 结果获取与异常处理

高级结果处理

FutureTask<String> task = new FutureTask<>(() -> {
    if (new Random().nextBoolean()) {
        throw new IOException("Simulated error");
    }
    return "Success";
});

new Thread(task).start();

try {
    // 带超时的结果获取
    String result = task.get(5, TimeUnit.SECONDS);
    System.out.println("Result: " + result);
} catch (TimeoutException e) {
    System.err.println("Operation timed out");
    task.cancel(true);
} catch (ExecutionException e) {
    Throwable cause = e.getCause();
    if (cause instanceof IOException) {
        System.err.println("I/O Error: " + cause.getMessage());
    }
}

3.3 作为Callable包装器

线程池集成

ExecutorService executor = Executors.newFixedThreadPool(4);

// 包装Callable任务
FutureTask<Double> piTask = new FutureTask<>(() -> {
    return Math.PI; // 复杂计算
});

// 提交到线程池
executor.submit(piTask);

// 获取结果
try {
    double pi = piTask.get();
    System.out.println("π ≈ " + pi);
} catch (InterruptedException | ExecutionException e) {
    e.printStackTrace();
} finally {
    executor.shutdown();
}

四、最佳实践

4.1 任务取消策略

优雅取消模式

FutureTask<Void> longRunningTask = new FutureTask<>(() -> {
    while (!Thread.currentThread().isInterrupted()) {
        // 执行增量工作
        try {
            TimeUnit.MILLISECONDS.sleep(100);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // 保持中断状态
        }
    }
    return null;
});

// 取消任务
if (!longRunningTask.cancel(true)) {
    System.out.println("Task already completed");
}

4.2 超时控制

超时重试机制

int retries = 3;
while (retries-- > 0) {
    try {
        return futureTask.get(1, TimeUnit.SECONDS);
    } catch (TimeoutException e) {
        System.out.println("Timeout, retrying...");
        if (!futureTask.cancel(true)) {
            futureTask = new FutureTask<>(task); // 创建新任务
            executor.execute(futureTask);
        }
    }
}

4.3 线程池集成优化

批量提交模式

ExecutorService executor = Executors.newWorkStealingPool();
List<FutureTask<Integer>> tasks = new ArrayList<>();

// 批量创建任务
for (int i = 0; i < 100; i++) {
    final int taskId = i;
    FutureTask<Integer> task = new FutureTask<>(() -> {
        return process(taskId);
    });
    tasks.add(task);
    executor.execute(task);
}

// 收集结果
List<Integer> results = new ArrayList<>();
for (FutureTask<Integer> task : tasks) {
    try {
        results.add(task.get());
    } catch (Exception e) {
        // 异常处理
    }
}

五、常见问题与解决方案

5.1 结果获取阻塞问题

解决方案

  • 使用get(long timeout, TimeUnit unit)设置超时
  • 在单独线程中执行get操作
  • 使用CompletionService管理结果

5.2 任务取消注意事项

关键点

  • 仅当任务处于NEW状态时可取消
  • 中断正在执行的任务需要任务配合
  • 取消后应清理相关资源

5.3 异常处理最佳实践

处理流程

  1. 通过ExecutionException.getCause()获取原始异常
  2. 区分已检查异常和运行时异常
  3. 记录异常上下文信息
  4. 执行补偿操作(如重试、降级)

六、源码关键逻辑

  1. 状态机转换

    • 通过 CAS 操作保证状态转换的原子性(如 NEWCOMPLETINGNORMAL)。
  2. 等待队列

    • 使用 WaitNode 链表管理等待线程,通过 UNSAFE.parkUNSAFE.unpark 实现线程阻塞和唤醒。
  3. 中断处理

    • cancel(true) 会中断执行任务的线程,但需任务内部响应中断(如检查 Thread.interrupted())。

七、总结

FutureTask 通过状态机和 CAS 操作实现了高效的异步任务管理。其源码核心在于:

  • 状态管理:通过 state 变量和 CAS 操作控制任务生命周期。
  • 结果回调:通过 set(result)setException(ex) 更新任务结果。
  • 线程协调:通过 WaitNode 队列和 UNSAFE 方法管理等待线程。

理解其源码有助于在并发编程中灵活控制异步任务,避免资源泄漏和死锁问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值