首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >100行手写FutureTask

100行手写FutureTask

作者头像
灬沙师弟
发布2025-11-12 13:44:37
发布2025-11-12 13:44:37
1250
举报
文章被收录于专栏:Java面试教程Java面试教程

一、前言

书接上文,先来看看需求

功能

实现方式

仅单线程执行任务

CAS 抢占 runner

阻塞获取结果

Treiber 栈 + LockSupport

支持取消/中断

状态机 + interrupt

异常透传

统一 outcome 字段

100 行以内

剔除了超时、批量栈清理等锦上添花逻辑


二、状态机(4 种简化状态)

代码语言:javascript
复制
private staticfinalint NEW          = 0;  // 新建
privatestaticfinalint COMPLETING   = 1;  // 结果已出,正在写入
privatestaticfinalint NORMAL       = 2;  // 正常结束
privatestaticfinalint EXCEPTIONAL  = 3;  // 异常结束
privatestaticfinalint CANCELLED    = 4;  // 被取消
privatestaticfinalint INTERRUPTING = 5;  // 中断中
privatestaticfinalint INTERRUPTED  = 6;  // 已中断

注:为了篇幅,超时/等待节点清理等状态略去。


三、核心字段一览

代码语言:javascript
复制
public class MiniFutureTask<V> implements Runnable, Future<V> {
    private volatile int state = NEW;           // 状态
    private Callable<V> callable;               // 业务
    private Object outcome;                     // 结果或异常
    private volatile Thread runner;             // 执行线程
    private volatile WaitNode waiters;          // Treiber 栈顶
}

四、Treiber 栈节点(无锁等待队列)

代码语言:javascript
复制
static final class WaitNode {
    volatile Thread thread = Thread.currentThread();
    volatile WaitNode next;
}

五、run() —— 单线程 CAS 执行

代码语言:javascript
复制
public void run() {
    if (state != NEW ||
        !UNSAFE.compareAndSwapObject(this, RUNNER_OFFSET, 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);
    }
}

六、set / setException —— 二次 volatile 写保证可见性

代码语言:javascript
复制
protected void set(V v) {
    if (UNSAFE.compareAndSwapInt(this, STATE_OFFSET, NEW, COMPLETING)) {
        outcome = v;
        STATE.setRelease(this, NORMAL);   // 顺序写
        finishCompletion();
    }
}

protected void setException(Throwable t) {
    if (UNSAFE.compareAndSwapInt(this, STATE_OFFSET, NEW, COMPLETING)) {
        outcome = t;
        STATE.setRelease(this, EXCEPTIONAL);
        finishCompletion();
    }
}

七、get() —— 阻塞等待

代码语言:javascript
复制
public V get() throws InterruptedException, ExecutionException {
    int s = state;
    if (s <= COMPLETING) s = awaitDone(false, 0L);
    return report(s);
}

private int awaitDone(boolean timed, long nanos) throws InterruptedException {
    long deadline = timed ? System.nanoTime() + nanos : 0L;
    WaitNode q = null;
    boolean queued = false;
    for (;;) {
        if (Thread.interrupted()) {
            removeWaiter(q);
            thrownew InterruptedException();
        }
        int s = state;
        if (s > COMPLETING) {
            if (q != null) q.thread = null;
            return s;
        }
        elseif (s == COMPLETING) Thread.yield();
        elseif (q == null) q = new WaitNode();
        elseif (!queued) {
            q.next = waiters;
            queued = UNSAFE.compareAndSwapObject(this, WAITERS_OFFSET, waiters, q);
        }
        elseif (timed) {
            long nanosLeft = deadline - System.nanoTime();
            if (nanosLeft <= 0L) {
                removeWaiter(q);
                return state;
            }
            LockSupport.parkNanos(this, nanosLeft);
        }
        else LockSupport.park(this);
    }
}

八、finishCompletion() —— 唤醒全部等待线程

代码语言:javascript
复制
private void finishCompletion() {
    for (WaitNode q; (q = waiters) != null;) {
        if (UNSAFE.compareAndSwapObject(this, WAITERS_OFFSET, q, null)) {
            for (;;) {
                Thread t = q.thread;
                if (t != null) {
                    q.thread = null;
                    LockSupport.unpark(t);
                }
                WaitNode next = q.next;
                if (next == null) break;
                q.next = null; // 方便 GC
                q = next;
            }
            break;
        }
    }
}

九、cancel() —— 中断或取消

代码语言:javascript
复制
public boolean cancel(boolean mayInterruptIfRunning) {
    if (!(state == NEW &&
          UNSAFE.compareAndSwapInt(this, STATE_OFFSET, NEW,
              mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
        returnfalse;
    try {
        if (mayInterruptIfRunning) {
            Thread t = runner;
            if (t != null) t.interrupt();
        }
    } finally {
        STATE.setRelease(this, INTERRUPTED);
        finishCompletion();
    }
    returntrue;
}

十、report() —— 结果或异常

代码语言:javascript
复制
@SuppressWarnings("unchecked")
private V report(int s) throws ExecutionException {
    Object x = outcome;
    if (s == NORMAL) return (V) x;
    if (s >= CANCELLED) throw new CancellationException();
    throw new ExecutionException((Throwable) x);
}

小结

  1. CAS 状态机保证单次执行
  2. 二次 volatile 写(COMPLETING → 终态)保障结果可见性
  3. Treiber 栈实现无锁等待队列
  4. LockSupport 负责线程阻塞与唤醒
  5. 异常与取消统一通过 outcome 字段透传

感谢关注!

给新朋友准备了这些干货,不管是提升技术还是跳槽涨薪都用得上:

1.Java 开发宝典:涵盖 Java 基础、Spring 全家桶、中间件(RabbitMQ/Kafka 等)、数据库(MySQL/Redis)、JVM 等核心内容

2.面试题:最新八股文 + 中大厂高频题,刷完面试有底、谈薪有底气

3.项目实战:商城 / 支付中心 / SSO 等可写进简历的项目

4.系统设计:今年最新场景题(订单 / 秒杀 / IM 等),帮你搞定面试设计难点

5.简历模板:大厂高薪模板,直接套用突出优势

扫下方二维码,无套路直接领!学习有问题或需要其他资料,随时找我~

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-10-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java面试教程 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、前言
  • 二、状态机(4 种简化状态)
  • 三、核心字段一览
  • 四、Treiber 栈节点(无锁等待队列)
  • 五、run() —— 单线程 CAS 执行
  • 六、set / setException —— 二次 volatile 写保证可见性
  • 七、get() —— 阻塞等待
  • 八、finishCompletion() —— 唤醒全部等待线程
  • 九、cancel() —— 中断或取消
  • 十、report() —— 结果或异常
  • 小结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档