创建线程的四种方式以及FutureTask解析

创建线程的四种方式以及FutureTask解析

1. 创建线程的四种方式
  1. 使用Thread创建

  2. 使用Runnable创建

  3. 使用Callable创建

  4. 使用线程池创建

Thread
public static void main(String[] args) {
    ThreadInnerDemo innerDemo = new ThreadInnerDemo();
    //执行Thread main - end
    innerDemo.run();
}

static class ThreadInnerDemo extends Thread{
    public void run(){
        System.out.printf("执行Thread %s - end",Thread.currentThread().getName());
        System.out.println("");
    }
}
Runnable
public static void main(String[] args) {
    Thread thread = new Thread(new Runnable2());
    //执行Thread main - end
    thread.run();
}

static class Runnable2 implements Runnable{
    @Override
    public void run() {
        System.out.printf("执行Runnable %s - end         ",Thread.currentThread().getName());
        System.out.println("");
    }
}
Callable
public static void main(String[] args) throws ExecutionException, InterruptedException {
        //使用Callable的时候要配合FutureTask或者线程池去使用,下面会介绍FutureTask在中间起了什么作用
        Callable2<Integer> callable2 = new Callable2<>();
        FutureTask<Integer> ft = new FutureTask<>(callable2);
        Thread thread = new Thread(ft);
        thread.run();
        System.out.println(ft.get());
        System.out.println(future.get());
    }


    static  class Callable2<Integer> implements Callable<java.lang.Integer> {
        @Override
        public java.lang.Integer call() throws Exception {
            System.out.printf("执行Runnable %s - end         ",Thread.currentThread().getName());
            System.out.println("");
            return 100;
        }
    }
线程池创建
public static void main(String[] args) throws ExecutionException, InterruptedException {
   //第一种类型,使用线程池去执行FutureTask
    Callable2<Integer> callable2 = new Callable2<>();
    FutureTask<Integer> ft = new FutureTask<>(callable2);
    ExecutorService service = Executors.newFixedThreadPool(1);
    service.submit(ft);
    System.out.println(ft.get());
    service.shutdown();

    //第二种直接使用jdk8封装好的CompletableFuture去执行线程,内部也是依赖线程池去执行。
    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        System.out.printf("执行Runnable %s - end         ", Thread.currentThread().getName());
        System.out.println("");
        return "12323";
    });
    System.out.println(future.get());
}
2. FutureTask解析
  1. 首先看看一下Futurn的类图,由下可以看出来,FutureTask实现了RunnableFuture接口,而RunnableFuture接口分别继承了Runnable和Future接口。
    在这里插入图片描述

首先我们分别看一下Runnable和Future接口

@FunctionalInterface
public interface Runnable {
   //定义线程执行块的逻辑
    public abstract void run();
}
//定义线程运行状态
public interface Future<V> {
    //用来取消任务的执行
    boolean cancel(boolean mayInterruptIfRunning);
	//判断任务是否已经取消
    boolean isCancelled();
	//判断任务是否已经执行完毕
    boolean isDone();
	//获取任务返回的结果
    V get() throws InterruptedException, ExecutionException;
	//获取任务返回的结果,并执行等待的时间,如果在指定时间没有返回结果,则会报错
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

public interface RunnableFuture<V> extends Runnable, Future<V> {
  	//运行入口
    void run();
}

  1. 接下来我们逐步分析FutureTask的运行过程

    //callable2 传入执行的callable代码块
    FutureTask<Integer> ft = new FutureTask<>(callable2);
    //调用构造函数来初始化callable和state状态,其中state代表任务执行的状态
    public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;
    }
    //除了上面的构造函数之外还有一个对Runnable提供的构造函数
    public FutureTask(Runnable runnable, V result) {
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;  
    }
    
    //看源码注释中标识了,任务执行状态可能出现的流转情况
    /**
     * Possible state transitions:
     * NEW -> COMPLETING -> NORMAL          任务执行正常的状态流转
     * NEW -> COMPLETING -> EXCEPTIONAL     任务执行异常的状态流转
     * NEW -> CANCELLED                     取消任务的状态流转
     * NEW -> INTERRUPTING -> INTERRUPTED   中断任务的状态流转
     */
    private static final int NEW          = 0; //初始状态。
    private static final int COMPLETING   = 1; //任务已经执行完成或者执行任务的时候发生异常
    private static final int NORMAL       = 2;//任务已经执行完成并且任务执行结果已经保存到outcome字段
    private static final int EXCEPTIONAL  = 3;//任务执行发生异常并且异常原因已经保存到outcome字段中后
    private static final int CANCELLED    = 4;//任务还没开始执行或者已经开始执行但是还没有执行完成的时候,用户调用了cancel(false)方法取消任务且不中断任务执行线程,这个时候状态会从NEW转化为CANCELLED状态。这是一个最终态。
    private static final int INTERRUPTING = 5;//调用了cancel(true)方法取消任务并且要中断任务执行线程但是还没有完全中断任务。(中间态)
    private static final int INTERRUPTED  = 6;//调用interrupt()中断任务执行线程之后状态会从INTERRUPTING转换到INTERRUPTED。
    
    run
    /**
    *  obj 需要更新的对象
    *  obj中整型filed的偏移量
    *  expect 期望的值
    *  update 修改的值
    */
    public final native boolean compareAndSwapObject(Object obj, long offset, Object expect, Object update);
    
    
    public void run() {
        //1.判断任务状态如果不是初始状态
        //2.则执行CSA,如果obj的offset等于null,则更新为当前线程
        //runnerOffset = UNSAFE.objectFieldOffset(k.getDeclaredField("runner")); 返回指定静态filed的内存地址和偏移量	
        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 {
                    //执行callable的call方法
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    //设置响应结果
                    set(result);
            }
        } finally {
            //设置runner为null
            runner = null;
            int s = state;
            //判断状态是否为中断,如果是,则执行线程中断逻辑
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }
    
    private void handlePossibleCancellationInterrupt(int s) {
        if (s == INTERRUPTING)
            while (state == INTERRUPTING)
                Thread.yield(); // wait out pending interrupt
    
    }
    
    protected void setException(Throwable t) {
        //设置状态为执行中
        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
            //设置outcome为异常
            outcome = t;
            //再将stateOffset设置为异常状态
            UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
            //调用完成方法
            finishCompletion();
        }
    }
    
    set
protected void set(V v) {
    //将状态NEW更新为COMPLETING
    if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) 
        //将callable的响应值赋值给outcome
        outcome = v;
    	//将stateOffset 更新为NORMAL,设置obj对象的offset偏移地址对应的整型field的值的指定值
        UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
        finishCompletion();
    }
}
private void finishCompletion(){
    // assert state > COMPLETING;
    // waitersOffset = UNSAFE.objectFieldOffset(k.getDeclaredField("waiters"));
    //在awaitDone()方法中设置了waiters,此时进到循环中
    for (WaitNode q; (q = waiters) != null;) {
        //不满足(q = waiters) != null 此条件,所以不进来
        if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
            for (;;) {
                Thread t = q.thread;
                if (t != null) {
                    q.thread = null;
                    //解锁awaitDone()阻塞的资源
                    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
}
get
public V get() throws InterruptedException, ExecutionException {
    int s = state;
    if (s <= COMPLETING)
        //如果状态小于或者等于1,则代表是任务初始状态或者正在执行阶段
        s = awaitDone(false, 0L);
    return report(s);
}

private int awaitDone(boolean timed, long nanos) throws InterruptedException {
    //截止时间为0
    final long deadline = timed ? System.nanoTime() + nanos : 0L;
    WaitNode q = null;
    boolean queued = false;
    for (;;) {
        //while循环,先判断线程是否中断,如果中断则在等待队列中删除该节点并抛出中断异常
        if (Thread.interrupted()) {
            //等待队列中删除该节点
            removeWaiter(q);
            throw new InterruptedException();
        }

        int s = state;
        //如果s大于1,代表任务已经结束
        if (s > COMPLETING) {
            if (q != null)
                q.thread = null;
            return s;
        }
        else if (s == COMPLETING) 
            //如果状态 =  COMPLETING 代表表示任务已经结束但是任务执行线程还没来得及给outcome赋值
            //这个时候让出执行权让其他线程优先执行
            Thread.yield();
        else if (q == null)
            //如果等待节点为空,则构造一个等待节点
            q = new WaitNode();
        else if (!queued)
            //如果还没有入队列,则把当前节点加入waiters首节点并替换原来waiters
            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
            //阻塞等待直到被其他线程唤醒,会在执行结束任务后,在finishCompletion()中唤醒次方法
            LockSupport.park(this);
    }
}
通过打断电发现,执行上面方法的过程中会循环3次,
    第一次:发现q == null,创建了q = new WaitNode();
    //设置new WaitNode()的next = waiters
    第二次:发现!queued,queued = UNSAFE.compareAndSwapObject(this, waitersOffset,q.next = waiters, q);
    第三次:LockSupport.park(this);当线程执行完后,唤醒次模块,会走到s > COMPLETING,代表线程执行结束


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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值