JDK 8 Future源码详解(详细注释版)

JDK 8 Future源码详解(详细注释版)

1. Future接口源码

/*
 * Future接口表示异步计算的结果
 * 提供了检查计算是否完成、等待计算完成以及获取计算结果的方法
 * 是Java并发编程中任务结果管理的核心接口
 */
public interface Future<V> {
    
    /**
     * 尝试取消任务的执行
     * 如果任务已经完成、已经被取消或由于其他原因无法取消,则此方法将返回false
     * 如果任务尚未开始执行,它应该永远不会运行
     * 如果任务已经开始执行,mayInterruptIfRunning参数决定是否应该中断执行任务的线程
     * 
     * @param mayInterruptIfRunning 如果执行该任务的线程应该被中断,则为true;否则,已经开始执行的任务应该被允许完成
     * @return 如果任务无法取消(通常是因为它已经正常完成),则返回false;否则返回true
     */
    boolean cancel(boolean mayInterruptIfRunning);
    
    /**
     * 判断任务是否在正常完成之前被取消
     * 
     * @return 如果任务在正常完成之前被取消,则返回true
     */
    boolean isCancelled();
    
    /**
     * 判断任务是否已完成
     * 完成可能意味着正常终止、异常或取消
     * 
     * @return 如果任务已完成,则返回true
     */
    boolean isDone();
    
    /**
     * 等待计算完成,然后获取其结果
     * 如果计算被取消,则抛出CancellationException
     * 如果计算抛出异常,则抛出ExecutionException
     * 如果当前线程在等待时被中断,则抛出InterruptedException
     * 
     * @return 计算结果
     * @throws CancellationException 如果计算被取消
     * @throws ExecutionException 如果计算抛出异常
     * @throws InterruptedException 如果当前线程在等待时被中断
     */
    V get() throws InterruptedException, ExecutionException;
    
    /**
     * 等待计算完成,最多等待给定的时间,然后获取其结果(如果可用)
     * 如果计算被取消,则抛出CancellationException
     * 如果计算抛出异常,则抛出ExecutionException
     * 如果超时,则抛出TimeoutException
     * 如果当前线程在等待时被中断,则抛出InterruptedException
     * 
     * @param timeout 等待的最长时间
     * @param unit 时间单位
     * @return 计算结果
     * @throws CancellationException 如果计算被取消
     * @throws ExecutionException 如果计算抛出异常
     * @throws InterruptedException 如果当前线程在等待时被中断
     * @throws TimeoutException 如果等待超时
     */
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

2. FutureTask核心实现类

/*
 * FutureTask是Future接口的基本实现
 * 可以包装Callable或Runnable对象
 * 因为实现了Runnable接口,所以可以提交给Executor执行
 */
public class FutureTask<V> implements RunnableFuture<V> {
    
    /*
     * 内部状态定义
     * 使用volatile保证内存可见性
     */
    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;  // 已中断状态
    
    // 底层任务,可以是Callable或Runnable
    private Callable<V> callable;
    
    // 结果或异常
    private Object outcome; // non-volatile, protected by state reads/writes
    
    // 执行任务的线程
    private volatile Thread runner;
    
    // 等待线程栈
    private volatile WaitNode waiters;
    
    /**
     * WaitNode内部类
     * 用于维护等待线程的链表
     */
    static final class WaitNode {
        volatile Thread thread;
        volatile WaitNode next;
        WaitNode() { thread = Thread.currentThread(); }
    }
    
    /**
     * 报告结果或抛出异常
     * 
     * @param s 当前状态
     * @return 计算结果
     * @throws ExecutionException 如果计算抛出异常
     * @throws CancellationException 如果任务被取消
     */
    @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);
    }
    
    /**
     * 构造方法 - 包装Callable对象
     * 
     * @param callable 要包装的Callable对象
     * @throws NullPointerException 如果callable为null
     */
    public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }
    
    /**
     * 构造方法 - 包装Runnable对象和结果
     * 
     * @param runnable 要包装的Runnable对象
     * @param result 任务完成时返回的结果
     * @throws NullPointerException 如果runnable为null
     */
    public FutureTask(Runnable runnable, V result) {
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;       // ensure visibility of callable
    }
    
    /**
     * 判断任务是否被取消
     */
    @Override
    public boolean isCancelled() {
        return state >= CANCELLED;
    }
    
    /**
     * 判断任务是否完成
     */
    @Override
    public boolean isDone() {
        return state != NEW;
    }
    
    /**
     * 取消任务
     * 
     * @param mayInterruptIfRunning 是否中断正在执行任务的线程
     * @return 如果任务被成功取消,则返回true
     */
    @Override
    public boolean cancel(boolean mayInterruptIfRunning) {
        // 如果任务已完成或已取消,直接返回false
        if (!(state == NEW &&
              UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
                  mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
            return false;
        try {    // in case call to interrupt throws exception
            if (mayInterruptIfRunning) {
                try {
                    Thread t = runner;
                    if (t != null)
                        t.interrupt();
                } finally { // final state
                    UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
                }
            }
        } finally {
            finishCompletion();
        }
        return true;
    }
    
    /**
     * 等待任务完成并获取结果
     */
    @Override
    public V get() throws InterruptedException, ExecutionException {
        int s = state;
        // 如果任务未完成,等待完成
        if (s <= COMPLETING)
            s = awaitDone(false, 0L);
        return report(s);
    }
    
    /**
     * 等待任务完成并获取结果,带超时控制
     */
    @Override
    public V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException {
        if (unit == null)
            throw new NullPointerException();
        int s = state;
        if (s <= COMPLETING &&
            (s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
            throw new TimeoutException();
        return report(s);
    }
    
    /**
     * 等待任务完成的核心方法
     * 
     * @param timed 是否启用超时控制
     * @param nanos 等待时间(纳秒)
     * @return 任务完成时的状态
     * @throws InterruptedException 如果等待时被中断
     */
    private int awaitDone(boolean timed, long nanos)
        throws InterruptedException {
        final long deadline = timed ? System.nanoTime() + nanos : 0L;
        WaitNode q = null;
        boolean queued = false;
        for (;;) {
            // 如果线程被中断,移除等待节点并抛出异常
            if (Thread.interrupted()) {
                removeWaiter(q);
                throw new InterruptedException();
            }
            
            int s = state;
            // 如果任务已完成,返回状态
            if (s > COMPLETING) {
                if (q != null)
                    q.thread = null;
                return s;
            }
            // 如果任务正在完成中,让出CPU时间片
            else if (s == COMPLETING) // cannot time out yet
                Thread.yield();
            // 如果还没有创建等待节点,创建一个
            else if (q == null)
                q = new WaitNode();
            // 如果还没有入队,将等待节点加入等待队列
            else if (!queued)
                queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
                                                     q.next = waiters, q);
            // 如果启用了超时控制,检查是否超时
            else if (timed) {
                nanos = deadline - System.nanoTime();
                if (nanos <= 0L) {
                    removeWaiter(q);
                    return state;
                }
                LockSupport.parkNanos(this, nanos);
            }
            // 否则阻塞等待
            else
                LockSupport.park(this);
        }
    }
    
    /**
     * 移除等待节点
     * 
     * @param node 要移除的节点
     */
    private void removeWaiter(WaitNode node) {
        if (node != null) {
            node.thread = null;
            retry:
            for (;;) {          // restart on removeWaiter race
                for (WaitNode pred = null, q = waiters, s; q != null; q = s) {
                    s = q.next;
                    if (q.thread != null)
                        pred = q;
                    else if (pred != null) {
                        pred.next = s;
                        if (pred.thread == null) // check for race
                            continue retry;
                    }
                    else if (!UNSAFE.compareAndSwapObject(this, waitersOffset,
                                                          q, s))
                        continue retry;
                }
                break;
            }
        }
    }
    
    /**
     * 任务执行完成后的清理工作
     */
    private void finishCompletion() {
        // assert state > COMPLETING;
        for (WaitNode q; (q = waiters) != null;) {
            if (UNSAFE.compareAndSwapObject(this, waitersOffset, 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; // unlink to help gc
                    q = next;
                }
                break;
            }
        }
        
        done();
        
        callable = null;        // to reduce footprint
    }
    
    /**
     * 钩子方法,在任务完成后调用
     * 可以被子类重写
     */
    protected void done() { }
    
    /**
     * 设置任务结果
     * 
     * @param v 任务结果
     */
    protected void set(V v) {
        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
            outcome = v;
            UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
            finishCompletion();
        }
    }
    
    /**
     * 设置任务异常
     * 
     * @param t 任务异常
     */
    protected void setException(Throwable t) {
        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
            outcome = t;
            UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
            finishCompletion();
        }
    }
    
    /**
     * 执行任务的核心方法
     * 实现了Runnable接口
     */
    @Override
    public void run() {
        // 如果任务状态不是NEW或者无法设置runner线程,直接返回
        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,直到状态被完成保护
            runner = null;
            // state必须在清空runner后读取,以防泄漏
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }
    
    /**
     * 执行任务并重置状态
     * 主要用于ScheduledThreadPoolExecutor中的周期性任务
     * 
     * @return 如果任务正常执行完成,则返回true
     */
    protected boolean runAndReset() {
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            return false;
        boolean ran = false;
        int s = state;
        try {
            Callable<V> c = callable;
            if (c != null && s == NEW) {
                try {
                    c.call(); // don't set result
                    ran = true;
                } catch (Throwable ex) {
                    setException(ex);
                }
            }
        } finally {
            runner = null;
            s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
        return ran && s == NEW;
    }
    
    /**
     * 处理可能的取消中断
     * 
     * @param s 当前状态
     */
    private void handlePossibleCancellationInterrupt(int s) {
        // 在中断者和取消者之间进行二次检查
        if (s == INTERRUPTING)
            while (state == INTERRUPTING)
                Thread.yield(); // wait out pending interrupt
    }
    
    // Unsafe mechanics
    private static final sun.misc.Unsafe UNSAFE;
    private static final long stateOffset;
    private static final long runnerOffset;
    private static final long waitersOffset;
    static {
        try {
            UNSAFE = sun.misc.Unsafe.getUnsafe();
            Class<?> k = FutureTask.class;
            stateOffset = UNSAFE.objectFieldOffset
                (k.getDeclaredField("state"));
            runnerOffset = UNSAFE.objectFieldOffset
                (k.getDeclaredField("runner"));
            waitersOffset = UNSAFE.objectFieldOffset
                (k.getDeclaredField("waiters"));
        } catch (Exception e) {
            throw new Error(e);
        }
    }
}

3. RunnableFuture接口源码

/*
 * RunnableFuture接口继承了Runnable和Future接口
 * 表示既可运行又可获取结果的Future
 */
public interface RunnableFuture<V> extends Runnable, Future<V> {
    /**
     * 将此Future设置为其计算结果,除非已被取消
     */
    void run();
}

4. ScheduledFuture接口源码

/*
 * ScheduledFuture接口继承了Delayed和Future接口
 * 表示ScheduledExecutorService延迟任务的结果
 */
public interface ScheduledFuture<V> extends Delayed, Future<V> {
    // 继承Delayed接口的getDelay方法
    // 继承Future接口的所有方法
}

5. CompletableFuture源码(Java 8新增)

/*
 * CompletableFuture是Java 8新增的Future实现
 * 提供了更强大的异步编程能力,支持函数式编程风格
 */
public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {
    
    /*
     * 内部状态和字段
     */
    volatile Object result;       // 结果或异常
    volatile Completion next;     // 依赖操作链表
    
    // 静态常量
    private static final AltResult NIL = new AltResult(null);
    
    /**
     * AltResult内部类
     * 用于包装异常结果
     */
    static final class AltResult {
        final Throwable ex; // null only for NIL
        AltResult(Throwable x) { this.ex = x; }
    }
    
    /**
     * Completion内部类
     * 表示依赖操作的基类
     */
    abstract static class Completion extends ForkJoinTask<Void>
        implements Runnable, AsynchronousCompletionTask {
        volatile Completion next;
        
        abstract boolean isLive();
        abstract boolean exec();
        
        @Override
        public final Void getRawResult() { return null; }
        @Override
        public final void setRawResult(Void v) {}
        @Override
        public final boolean exec() { return exec(); }
    }
    
    /*
     * 核心方法实现
     */
    
    /**
     * 构造方法
     */
    public CompletableFuture() {
    }
    
    /**
     * 创建已完成的CompletableFuture
     */
    public static <U> CompletableFuture<U> completedFuture(U value) {
        return new CompletableFuture<U>((value == null) ? NIL : value);
    }
    
    /**
     * 私有构造方法,用于创建已完成的CompletableFuture
     */
    private CompletableFuture(Object r) {
        this.result = r;
    }
    
    /**
     * 判断任务是否完成
     */
    @Override
    public boolean isDone() {
        return result != null;
    }
    
    /**
     * 获取任务结果
     */
    @Override
    @SuppressWarnings("unchecked")
    public T get() throws InterruptedException, ExecutionException {
        Object r;
        if ((r = result) == null)
            r = waitingGet(true);
        return (T) reportGet(r);
    }
    
    /**
     * 带超时的获取任务结果
     */
    @Override
    @SuppressWarnings("unchecked")
    public T get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException {
        Object r;
        if ((r = result) == null)
            r = timedAwaitDone(unit.toNanos(timeout), true);
        return (T) reportGet(r);
    }
    
    /**
     * 非阻塞获取任务结果
     */
    public T getNow(T valueIfAbsent) {
        Object r;
        return ((r = result) == null) ? valueIfAbsent : (T) reportJoin(r);
    }
    
    /**
     * 判断任务是否被取消
     */
    @Override
    public boolean isCancelled() {
        Object r;
        return ((r = result) instanceof AltResult) &&
            (((AltResult)r).ex instanceof CancellationException);
    }
    
    /**
     * 取消任务
     */
    @Override
    public boolean cancel(boolean mayInterruptIfRunning) {
        boolean cancelled = (result == null) &&
            internalComplete(new AltResult(new CancellationException()));
        if (cancelled)
            postComplete();
        return cancelled;
    }
    
    /**
     * 异步执行任务
     */
    public CompletableFuture<Void> thenRun(Runnable action) {
        return uniRunStage(defaultExecutor(), action);
    }
    
    /**
     * 异步执行任务并获取结果
     */
    public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn) {
        return uniApplyStage(defaultExecutor(), fn);
    }
    
    /**
     * 异步执行任务并消费结果
     */
    public CompletableFuture<Void> thenAccept(Consumer<? super T> action) {
        return uniAcceptStage(defaultExecutor(), action);
    }
    
    /**
     * 组合两个CompletableFuture
     */
    public <U> CompletableFuture<U> thenCompose(
        Function<? super T, ? extends CompletionStage<U>> fn) {
        return uniComposeStage(defaultExecutor(), fn);
    }
    
    /**
     * 等待所有CompletableFuture完成
     */
    public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs) {
        return andTree(cfs, 0, cfs.length - 1);
    }
    
    /**
     * 等待任意一个CompletableFuture完成
     */
    public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs) {
        return orTree(cfs, 0, cfs.length - 1);
    }
    
    /**
     * 异步执行任务
     */
    public CompletableFuture<T> thenRunAsync(Runnable action) {
        return uniRunStage(defaultExecutor(), action);
    }
    
    /**
     * 使用指定执行器异步执行任务
     */
    public CompletableFuture<T> thenRunAsync(Runnable action,
                                             Executor executor) {
        return uniRunStage(screenExecutor(executor), action);
    }
    
    /**
     * 完成CompletableFuture
     */
    public boolean complete(T value) {
        boolean triggered = internalComplete((value == null) ? NIL : value);
        if (triggered)
            postComplete();
        return triggered;
    }
    
    /**
     * 以异常完成CompletableFuture
     */
    public boolean completeExceptionally(Throwable ex) {
        if (ex == null) throw new NullPointerException();
        boolean triggered = internalComplete(new AltResult(ex));
        if (triggered)
            postComplete();
        return triggered;
    }
    
    // 内部辅助方法...
    
    private Object waitingGet(boolean interruptible) {
        // 简化的等待实现
        synchronized (this) {
            while (result == null) {
                try {
                    wait();
                } catch (InterruptedException ex) {
                    if (interruptible)
                        throw new RuntimeException(ex);
                }
            }
        }
        return result;
    }
    
    private Object timedAwaitDone(long nanos, boolean interruptible)
        throws TimeoutException {
        // 简化的带超时等待实现
        synchronized (this) {
            long startTime = System.nanoTime();
            while (result == null) {
                long remaining = nanos - (System.nanoTime() - startTime);
                if (remaining <= 0)
                    throw new TimeoutException();
                try {
                    wait(remaining / 1000000, (int)(remaining % 1000000));
                } catch (InterruptedException ex) {
                    if (interruptible)
                        throw new RuntimeException(ex);
                }
            }
        }
        return result;
    }
    
    private static Object reportGet(Object r)
        throws InterruptedException, ExecutionException {
        if (r == null) // by convention below, null means interrupted
            throw new InterruptedException();
        if (r instanceof AltResult) {
            Throwable x, cause;
            if ((x = ((AltResult)r).ex) == null)
                return null;
            if (x instanceof CancellationException)
                throw (CancellationException)x;
            if ((cause = x.getCause()) != null)
                x = cause;
            throw new ExecutionException(x);
        }
        return r;
    }
    
    private static Object reportJoin(Object r) {
        if (r instanceof AltResult) {
            Throwable x;
            if ((x = ((AltResult)r).ex) == null)
                return null;
            if (x instanceof CancellationException)
                throw (CancellationException)x;
            throw new CompletionException(x);
        }
        return r;
    }
    
    private boolean internalComplete(Object value) {
        synchronized (this) {
            if (result == null) {
                result = value;
                notifyAll();
                return true;
            }
            return false;
        }
    }
    
    private void postComplete() {
        // 触发依赖操作的完成
    }
}

6. 使用示例

/**
 * Future使用示例
 */
public class FutureExample {
    
    public static void main(String[] args) {
        // 创建ExecutorService
        ExecutorService executor = Executors.newFixedThreadPool(2);
        
        // 提交Callable任务
        Future<Integer> future = executor.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                // 模拟耗时操作
                Thread.sleep(2000);
                return 42;
            }
        });
        
        try {
            // 非阻塞检查任务是否完成
            System.out.println("Task completed: " + future.isDone());
            
            // 阻塞等待结果
            Integer result = future.get(3, TimeUnit.SECONDS);
            System.out.println("Result: " + result);
            
        } catch (InterruptedException e) {
            System.out.println("Task was interrupted");
            Thread.currentThread().interrupt();
        } catch (ExecutionException e) {
            System.out.println("Task execution failed: " + e.getCause());
        } catch (TimeoutException e) {
            System.out.println("Task timed out");
        } finally {
            executor.shutdown();
        }
    }
}

/**
 * CompletableFuture使用示例
 */
public class CompletableFutureExample {
    
    public static void main(String[] args) {
        // 创建已完成的CompletableFuture
        CompletableFuture<String> completedFuture = 
            CompletableFuture.completedFuture("Hello");
        
        // 异步执行任务
        CompletableFuture<String> future = CompletableFuture
            .supplyAsync(() -> {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                return "World";
            })
            .thenApply(String::toUpperCase)
            .thenCombine(completedFuture, (s1, s2) -> s2 + " " + s1);
        
        // 等待结果
        future.thenAccept(System.out::println);
        
        // 组合多个CompletableFuture
        CompletableFuture<String> future1 = CompletableFuture
            .supplyAsync(() -> "Task1");
        CompletableFuture<String> future2 = CompletableFuture
            .supplyAsync(() -> "Task2");
            
        CompletableFuture<Void> allFutures = CompletableFuture
            .allOf(future1, future2);
            
        allFutures.thenRun(() -> {
            try {
                System.out.println("All tasks completed: " + 
                    future1.get() + ", " + future2.get());
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        
        // 等待足够时间让异步任务完成
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

7. 核心设计要点总结

7.1 状态管理

  • 使用整数状态机管理任务生命周期
  • 状态转换:NEW → COMPLETING → NORMAL/EXCEPTIONAL/CANCELLED
  • 通过CAS操作保证线程安全的状态更新

7.2 等待机制

  • 使用LockSupport.park/unpark实现线程阻塞和唤醒
  • 维护等待线程链表,支持多个线程等待同一任务
  • 提供带超时的等待机制

7.3 内存可见性

  • 使用volatile关键字保证字段的内存可见性
  • 通过Unsafe类进行原子操作
  • 合理的内存屏障使用

7.4 异常处理

  • 区分正常完成、异常完成和取消状态
  • 提供详细的异常信息传递机制
  • 支持CancellationException和ExecutionException

7.5 CompletableFuture增强

  • 支持函数式编程风格
  • 提供丰富的链式调用方法
  • 支持组合多个异步操作
  • 非阻塞的异步编程模型

这些设计使得Future接口及其实现成为Java并发编程中不可或缺的工具,为异步任务的管理和结果获取提供了强大而灵活的支持。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值