JAVA异步编程-JDK中FutureTask实践与原理

1.文章目录

  1. Future接口概述
  2. FutureTask概述
  3. FutureTask显式线程,线程池实现;
  4. FutureTask类结构,源码导读;
  5. FutureTask局限性;

2.JDK 中Future

public interface Future<V> {

    // 取消任务
    boolean cancel(boolean mayInterruptIfRunning);

    // 任务是否取消
    boolean isCancelled();

    // 任务是否结束
    boolean isDone();

    // 获取任务结果
    V get() throws InterruptedException, ExecutionException;

    // timeOunt时间内获取结果
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}
  • V get() throws InterruptedException, ExecutionException;等待异步计算结果任务完成,返回结果;如果任务没有完成,阻塞当前线程直到任务结束;如果等待任务结果的过程中有其他线程取消了任务,抛出CancellationException;被中断抛出InteeuptionException异常;如果计算出现异常,抛出ExecutionException异常;
  •  V get(long timeout, TimeUnit unit)throws InterruptedException, ExecutionException, TimeoutException;同get方法,多加了一个timeOut,如果等待任务结果时间超出timeOut则会抛出timeOunt异常;
  •  boolean isDone();如果任务计算完成返回true,否则false;
  • boolean cancel(boolean mayInterruptIfRunning);尝试取消任务,如果当前线程已经完成任务/被其他线程取消,则尝试取消任务失败;如果任务还没有执行,则任务就不会再执行;如果任务已经执行,根据mayInterruptIfRunning参数确定是否打断正在运行的线程;
  •   boolean isCancelled();如果任务再执行完毕前被取消了,则该方法返回true;

3.FutureTask概述

  • FutureTask代表一个可被取消的异步计算任务,该类实现了Future接口,提供任务启动,取消,查询任务是否完成,获取计算结果的接口;
  • FutureTask的结果只能等到任务完成才可以获取,使用get方法系列,当结果没有出来,线程调用get系列方法会被阻塞。FutureTask的任务可以是Callable类型,也可以是Runnable接口;

4.显式使用线程完成FutureTask任务

package AsynchronousProgramming;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * @Author: SoftWareKang
 * @Name:JAVALEARN
 * @Date: 2020/6/1 19:38
 */
public class AsyncFutureExample {

    public static String doSomeThingA(){
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("-- do someThing A--");

        return "TaskAResult";
    }

    public static String doSomethingB(){
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("-- do someThing B--");

        return "TaskBResult";
    }

    public static void main(String[] argv) throws ExecutionException, InterruptedException {
        long start = System.currentTimeMillis();

        // 创建FutureTask
        FutureTask<String> futureTask = new FutureTask<>(() -> {
            String result = null;
            try {
                result = doSomeThingA();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return result;
        });

        // 使用线程执行任务A
        new Thread(futureTask, "thredA").start();

        // 执行任务B
        String resultB = doSomethingB();

        // 等待futureTask结果
        String resultA = futureTask.get();

        System.out.println(resultA + ":"+ resultB);

        System.out.println(System.currentTimeMillis() - start);

    }
}

5.线程池执行FutureTask任务

package AsynchronousProgramming;

import java.util.concurrent.*;

/**
 * @Author: SoftWareKang
 * @Name:JAVALEARN
 * @Date: 2020/6/1 19:51
 */
public class AsncFutureTaskByThreadPool {
    // 获取CPU数
    private final static int AVALIABLE_PROCESSORS = Runtime.getRuntime().availableProcessors();
    // 自定义线程池
    private final static ThreadPoolExecutor POOL_EXECUTOR = new ThreadPoolExecutor(AVALIABLE_PROCESSORS, 2 * AVALIABLE_PROCESSORS,
            1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(5), new ThreadPoolExecutor.CallerRunsPolicy());


    public static String doSomeThingA(){
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("-- do someThing A--");

        return "TaskAResult";
    }

    public static String doSomethingB(){
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("-- do someThing B--");

        return "TaskBResult";
    }

    public static void main(String[] argv) throws ExecutionException, InterruptedException {
        long start = System.currentTimeMillis();

        // 创建FutureTask
        FutureTask<String> futureTask = new FutureTask<>(() -> {
            String result = null;
            try {
                result = doSomeThingA();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return result;
        });

        // 线程池执行
        POOL_EXECUTOR.execute(futureTask);

        // 执行任务B
        String resultB = doSomethingB();

        // 同步等待线程A结束
        String resultA = futureTask.get();
        // 打印结果
        System.out.println(resultA + ":" + resultB);
        System.out.println(System.currentTimeMillis() - start);

        // 关闭线程池
        POOL_EXECUTOR.shutdownNow();

    }
}

6.FutureTask类结构&源码导读

基本属性:

    // 任务的几种状态
    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 Callable<V> callable;
    // 任务运行结果
    private Object outcome; // non-volatile, protected by state reads/writes
    // 运行该任务的线程
    private volatile Thread runner;
    //无锁栈,记录等待任务结果的线程节点
    private volatile WaitNode waiters;

   // Unsafe mechanics
    private static final sun.misc.Unsafe UNSAFE;
    // state变量的偏移量
    private static final long stateOffset;
    // runner变量的偏移量
    private static final long runnerOffset;
    // waiters变量的偏移地址
    private static final long waitersOffset;
    static {
        try {
            // 获取unsafe实例
            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);
        }
    }
  • 任务初始为new;可以通过set,setExpection,cancel函数设置任务结果,任务会转化为终止状态;
  • NEW->COMPLETING->NORMAL;正常终止流程转化。
  • NEW->COMPLETING->EXCEPTIONAL:执行任务发生异常流程转化;
  • NEW->CANCELLED:任务还没开始就被取消;
  • NEW->INTERRUPTING->INTERRUPTED:任务被中断;
  • 另外FutureTask使用UnSafe机制操作内存变量,记录变量的偏移地址,方便后面CAS操作赋值;

WaitNode:一个列表,记录被阻塞的链表;

 static final class WaitNode {
        volatile Thread thread;
        volatile WaitNode next;
        WaitNode() { thread = Thread.currentThread(); }
    }

构造函数:

 public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }
public static <T> Callable<T> callable(Runnable task, T result) {
        if (task == null)
            throw new NullPointerException();
        return new RunnableAdapter<T>(task, result);
    }
 static final class RunnableAdapter<T> implements Callable<T> {
        final Runnable task;
        final T result;
        RunnableAdapter(Runnable task, T result) {
            this.task = task;
            this.result = result;
        }
        public T call() {
            task.run();
            return result;
        }
    }
  • 第二种初始化,方式用适配器模式做了转化,Runnable->Callable

Run:任务的执行体,线程调用这个方法来运行具体任务,最后讲结果赋值给outcome

public void run() {
        // 如果任务不是NEW,或者使用CAS设置Runner失败,直接返回
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            // 如果任务不为Null,state=new则执行任务
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    // 执行任务,设置ran为true
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    // 异常
                    result = null;
                    ran = false;
                    setException(ex);
                }
                // 如果正常运行,则赋值
                if (ran)
                    set(result);
            }
        } finally {
            // runner must be non-null until state is settled to
            // prevent concurrent calls to run()
            runner = null;
            // state must be re-read after nulling runner to prevent
            // leaked interrupts
            // 为了让调用cancle(true)的线程在该方法return前中断
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }

handlePossibleCancellationInterrupt:在返回前中断;

 private void handlePossibleCancellationInterrupt(int s) {
       // 为了让其他线程中断这个线程:不断轮询,让出cpu使用权限
        if (s == INTERRUPTING)
            while (state == INTERRUPTING)
                Thread.yield(); // wait out pending interrupt
    }

setException方法:设置异常信息

 protected void setException(Throwable t) {
        // CAS设置state状态为COMPLETING
        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
            // outcome设置异常信息
            outcome = t;
            // 设置state状态为异常状态
            UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
            // 最后处理:waiter链表里面的线程节点
            finishCompletion();
        }
    }

finishCompletion:激活链表里面的线程节点

private void finishCompletion() {
        // assert state > COMPLETING;
        for (WaitNode q; (q = waiters) != null;) {
           // 设置waiter为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
        callable = null;        // to reduce footprint
    }

set(V v)正常运行设置

 protected void set(V v) {
        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
             // 设置结果
            outcome = v;
            // 设置状态为正常
            UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
            finishCompletion();
        }
    }

get方法:获取任务结果,如果没运行完,阻塞调用线程;

public V get() throws InterruptedException, ExecutionException {
        int s = state;
        // 如果状态<=COMPLETING,表示还没运行完
        if (s <= COMPLETING)
            // 调用awaitDone,任务终止
            s = awaitDone(false, 0L);
       // 返回结果
        return report(s);
    }
private int awaitDone(boolean timed, long nanos):
 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();
            }
            // 如果s》COMPLETING:表示任务已经执行完了
            int s = state;
            if (s > COMPLETING) {
                // q不为null,置为null
                if (q != null)
                    q.thread = null;
                return s;
            }
            // 如果任务状态为COMPLETING,释放cpu
            else if (s == COMPLETING) // cannot time out yet
                Thread.yield();
            else if (q == null)
                // 创建wait节点
                q = new WaitNode();
            else if (!queued)
                // 如果没有入队,则插入waiter链表尾部,CAS方式
                queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
                                                   q.next = waiters, q);
           //如果有超时设置,则LclSupport.parkNanos进行等待,超时抛出异常
            else if (timed) {
                nanos = deadline - System.nanoTime();
                if (nanos <= 0L) {
                    removeWaiter(q);
                    return state;
                }
                LockSupport.parkNanos(this, nanos);
            }
            else
                // 阻塞
                LockSupport.park(this);
        }
    }

cancel(boolean myInterrruptIfRunning):myInterrruptIfRunning确定是否中断正在执行的线程;

public boolean cancel(boolean mayInterruptIfRunning) {
        // 设置任务状态
        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;
    }
  • 到此重要的方法已经导读完了

7.FutureTask局限性

  • 为了Future获取结果,我们必须调用get方法,会阻塞调用线程,这不是很理想
  • 我们理想的:可以将多个异步结果变成一个;可以将一个的结果作为下一个任务的参数;可以手动设置Future的结果;
  • 为了克服这些问题:JDK8提出了CompletableFuture,后续对这个进行实践&源码导读;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章