【多线程】FutureTask多线程底层实现

MyFutureTask最简版本实现思路
文章目录
1-DeepSeek版本-MyFutureTask
要实现 MyFutureTask<V>,需要理解它作为 RunnableFuture 的双重身份:既是 Runnable(可被线程执行),又是 Future(提供异步结果获取)。最小实现的核心是状态管理 和等待/通知机制,下面给出设计思路和最小代码。
设计思路
- 任务持有
- 通过
Callable<V>封装实际任务(也可通过Runnable + result构造)。 - 若使用
Runnable,可通过Executors.callable(runnable, result)转换为Callable。
- 通过
- 执行状态
- 使用
volatile boolean done标记是否完成(正常/异常/取消均视为完成)。 - 使用
volatile boolean cancelled标记是否被取消。 - 保存执行结果
V result或异常Throwable exception。
- 使用
- 线程安全
- 所有状态变更和条件等待均通过
synchronized(this)保护。 - 使用
wait()/notifyAll()实现get()的阻塞等待。
- 所有状态变更和条件等待均通过
run()方法- 执行前检查是否已完成,避免重复执行。
- 记录当前执行线程
runner(用于支持中断,最小实现可保留)。 - 调用
callable.call(),正常完成则设置result,异常则设置exception。 - 无论结果如何,最后标记
done = true并唤醒所有等待线程。
cancel()方法- 若已完成则返回
false。 - 否则标记
cancelled = true和done = true(阻止后续执行)。 - 若
mayInterruptIfRunning为true且runner非空,则中断该线程。 - 唤醒等待线程。
- 若已完成则返回
get()方法- 在
synchronized块中循环检查done,未完成则wait()。 - 完成后检查
cancelled或exception,分别抛出CancellationException或ExecutionException。 - 否则返回
result。
- 在
- 超时
get()- 最小实现可暂不实现,或使用
wait(long timeout)简单处理。
- 最小实现可暂不实现,或使用
最小版本代码实现
java
import java.util.concurrent.*;
public class MyFutureTask<V> implements RunnableFuture<V> {
private final Callable<V> callable;
private V result;
private Throwable exception;
private volatile boolean done;
private volatile boolean cancelled;
private Thread runner; // 用于支持中断
// 构造:通过 Callable
public MyFutureTask(Callable<V> callable) {
this.callable = callable;
}
// 构造:通过 Runnable + 结果
public MyFutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
}
@Override
public void run() {
// 双重检查,防止已取消或已完成的任务被执行
if (done) return;
synchronized (this) {
if (done) return;
runner = Thread.currentThread();
}
try {
V v = callable.call();
synchronized (this) {
result = v;
done = true;
notifyAll(); // 唤醒等待 get() 的线程
}
} catch (Throwable t) {
synchronized (this) {
exception = t;
done = true;
notifyAll();
}
} finally {
runner = null;
}
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
if (done) return false;
synchronized (this) {
if (done) return false;
cancelled = true;
done = true; // 标记完成,阻止后续执行
if (mayInterruptIfRunning && runner != null) {
runner.interrupt();
}
notifyAll();
return true;
}
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public boolean isDone() {
return done;
}
@Override
public V get() throws InterruptedException, ExecutionException {
synchronized (this) {
while (!done) {
wait(); // 等待任务完成
}
}
if (cancelled) {
throw new CancellationException();
}
if (exception != null) {
throw new ExecutionException(exception);
}
return result;
}
// 最小版本暂不实现超时 get,可留空或简单实现
@Override
public V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
// 如需支持可参考如下:
// long nanos = unit.toNanos(timeout);
// synchronized (this) {
// while (!done) {
// if (nanos <= 0) throw new TimeoutException();
// nanos = wait(nanos); // 但 wait(long) 以毫秒计,建议使用 LockSupport
// }
// }
// ... 同上的后续处理
throw new UnsupportedOperationException("超时 get 暂未实现");
}
}
关键点说明
- 状态原子性 :
done和cancelled用volatile保证可见性,但复合操作(如检查+修改)仍需synchronized。 - 中断支持 :
runner记录当前执行线程,cancel可尝试中断,但任务本身需响应中断(本例中Callable需自行处理中断)。 - 超时版本 :可基于
wait(long)或LockSupport实现,但为保持最小,此处仅提供骨架。 - 异常处理 :执行期间抛出的任何
Throwable都会被封装为ExecutionException抛出。
这个最小实现涵盖了 Future 的核心契约,可满足简单的异步任务需求,实际生产环境建议直接使用 java.util.concurrent.FutureTask。
2-Kimi版本-MyFutureTask
public class MyFutureTask<V> implements RunnableFuture<V> {}
假如我想写一个简单的MyFutureTask实现,我的代码编写思路应该是什么,给我一个最小版本的代码实现
实现 MyFutureTask 的核心思路是:它既是 Runnable(能被线程执行),又是 Future(能拿到异步结果)。所以你需要同时搞定「任务执行」和「结果阻塞等待」两件事。
最小版本的关键设计点:
| 要解决的问题 | 最小实现方案 |
|---|---|
| 状态管理 | 用 volatile int state(0=NEW, 1=RUNNING, 2=DONE, 3=CANCELLED) |
| 阻塞等待结果 | synchronized + wait()/notifyAll() |
| 取消任务 | 记录执行线程 runner,调用 runner.interrupt() |
| 异常包装 | ExecutionException 包装业务异常 |
下面是一个可直接拷贝运行的最小版本:
java
import java.util.concurrent.*;
public class MyFutureTask<V> implements RunnableFuture<V> {
// 状态常量
private static final int NEW = 0;
private static final int RUNNING = 1;
private static final int DONE = 2;
private static final int CANCELLED = 3;
private volatile int state = NEW;
private Callable<V> callable;
private V result;
private Throwable exception;
private Thread runner; // 记录实际执行 run() 的线程,用于 cancel 时中断
public MyFutureTask(Callable<V> callable) {
if (callable == null) throw new NullPointerException();
this.callable = callable;
}
// ========== Runnable 接口 ==========
@Override
public void run() {
// 如果已经不是 NEW 状态,说明已经有人在跑了,直接返回
if (!casState(NEW, RUNNING)) return;
runner = Thread.currentThread();
try {
V r = callable.call();
setResult(r);
} catch (Throwable t) {
setException(t);
}
}
// ========== Future 接口 ==========
@Override
public V get() throws InterruptedException, ExecutionException {
synchronized (this) {
// 没完成就等着
while (state < DONE) {
wait();
}
return report();
}
}
@Override
public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
long nanos = unit.toNanos(timeout);
synchronized (this) {
if (state < DONE) {
if (nanos <= 0) throw new TimeoutException();
wait(nanos / 1_000_000, (int) (nanos % 1_000_000));
if (state < DONE) throw new TimeoutException();
}
return report();
}
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
synchronized (this) {
if (state >= DONE) return false; // 已经跑完了,取消无效
state = CANCELLED;
if (mayInterruptIfRunning && runner != null) {
runner.interrupt();
}
notifyAll(); // 唤醒所有在 get() 里 wait 的线程
return true;
}
}
@Override
public boolean isCancelled() {
return state == CANCELLED;
}
@Override
public boolean isDone() {
return state >= DONE;
}
// ========== 内部辅助方法 ==========
/** 非阻塞地尝试更新状态(简单版 CAS,用 synchronized 保证原子性) */
private boolean casState(int expect, int update) {
synchronized (this) {
if (state != expect) return false;
state = update;
return true;
}
}
/** 正常结束,设置结果 */
private void setResult(V v) {
synchronized (this) {
if (state == RUNNING) {
result = v;
state = DONE;
notifyAll();
}
}
}
/** 异常结束,设置异常 */
private void setException(Throwable t) {
synchronized (this) {
if (state == RUNNING) {
exception = t;
state = DONE;
notifyAll();
}
}
}
/** 根据最终状态返回结果或抛出异常 */
private V report() throws ExecutionException {
if (state == CANCELLED) throw new CancellationException();
if (exception != null) throw new ExecutionException(exception);
return result;
}
// ========== 演示 ==========
public static void main(String[] args) throws Exception {
// 1. 创建一个 Callable 任务
Callable<Integer> task = () -> {
System.out.println("[" + Thread.currentThread().getName() + "] 开始计算...");
Thread.sleep(1000);
return 42;
};
// 2. 包装成 MyFutureTask
MyFutureTask<Integer> futureTask = new MyFutureTask<>(task);
// 3. 丢给线程执行(因为它实现了 Runnable)
new Thread(futureTask, "Worker-1").start();
// 4. 主线程阻塞等待结果(因为它实现了 Future)
System.out.println("[" + Thread.currentThread().getName() + "] 等待结果...");
Integer result = futureTask.get();
System.out.println("结果: " + result);
// --- 取消演示 ---
MyFutureTask<Integer> futureTask2 = new MyFutureTask<>(() -> {
while (!Thread.currentThread().isInterrupted()) {
// 忙等,直到被中断
}
return 99;
});
new Thread(futureTask2).start();
Thread.sleep(50);
boolean cancelled = futureTask2.cancel(true);
System.out.println("取消成功? " + cancelled);
try {
futureTask2.get();
} catch (CancellationException e) {
System.out.println("确实被取消了,抛出了 CancellationException");
}
}
}
代码编写思路总结:
- 构造时存下
Callable:这是真正要执行的逻辑。JDK 源码里还会处理Runnable+ result 的情况,最小版只保留Callable即可。 run()里做状态竞争 :casState(NEW, RUNNING)保证同一个任务不会被多个线程重复执行。get()用wait()阻塞 :没完成就挂起,完成后notifyAll()唤醒。这是 JDK 源码的核心骨架(源码里用更复杂的LockSupport.park/unpark,但wait/notify足够演示原理)。cancel()中断执行线程 :记录runner引用,调用interrupt(),让Callable.call()里的阻塞操作(如sleep)能感知到中断。- 异常统一包成
ExecutionException:这是Future.get()的契约------业务异常不会直接抛,而是包一层。