Callable线程如何一步步执行的

目录

1. 背景

2. 案例: 

2.1 使用Callable线程步骤:

3. 代码设计分析

4. 深入Callable具体源码,一步步查看如何执行:

4.1 Callbale接口---FutureTask构造方法的接口

4.2 FutureTask类和内部重要方法 

4.3 RunnableFuture接口 ---继承了Runnable,Future接口

4.4 Runnable接口 

4.5 Future接口 

5. 为了能站在全局的角度来看,所以画了一张流程图,感觉好丑。。。


1. 背景

我们知道线程的实现方式有4种

1.继承Thread类

2.实现Runnable接口

3.实现Callable接口:与其他明显区别是有返回值。

4.线程池

本文讲述第三种的执行流程。

刚开始感觉实现Callable接口的方法有点复杂,好奇内部到底是怎么实现的,就看了以下源码,发现代码不难,但是思路很巧妙。

2. 案例: 

MyThread类实现Callable接口,泛型是返回对象的类型,这里是Integer

2.1 使用Callable线程步骤:

1.定义一个MyThread,实现Callable接口

2.重写call()方法:类似run()方法

3.创建FutureTask对象,构造方法参数是MyThread对象。

4.创建Thread对象,构造方法参数是MyThread对象。

5.开启线程

6.获取返回值,返回值保存在了FutureTask对象种,通过get()方法返回。

代码如下:

public class MyThread implements Callable<Integer>{

    @Override
    public Integer call() throws Exception {
        System.out.println("*************************");
        return 1024;
    }

    public static void main(String[] args)throws Exception{
        FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyThread());
        Thread thread = new Thread(futureTask); 
        thread.start();  //开启线程
        Integer result = futureTask.get();   //获取返回值
        System.out.println("result is ****"+result);  //打印
    }

}

测试结果: 

3. 代码设计分析

我们知道Thread的构造方法参数是Runnable接口,也就是new Thread(new Runnable())这种形式,但是我们的MyThread类没有实现Runnable接口,但是RunnableFuture继承了Runnable接口,而FutureTask又实现了Runnable,所以FutureTask可以向上转型为Runnable,并作为Thread构造方法参数传入。而Callable接口的call()方法又是如何与Runnable方法联系起来的的呢?答案是:Callable的实现类MyThread作为FutureTask(相当于Runnable)的构造方法的传入参数,而Runnable的run()方法内会调用call()方法,所以就联系起来了。

总结一下执行大体流程:

thread:start()====>thread:run()====>MyThread():call()====>FutureTask:set(result)====>FutureTask:report()====>FutureTask:get()方法返回result

4. 深入Callable相关具体源码,只贴重要的部分

代码是按顺序贴的,为了思路更加清楚,贴一下自己画的流程图(和后面的一张是一样的,这里放到前面了),有点丑,不想看的忽略。。。

4.1 Callbale接口---FutureTask构造方法的接口

@FunctionalInterface
public interface Callable<V> {
    
    V call() throws Exception;
}

4.2 FutureTask类和内部重要方法 

该类实现了RunnableFuture接口(而该接口又实现了Runnable接口,所以FutureTask可以作为Thread构造函数的参数向上转型为Runnable,这里面包含一种重要思想--运行时多态或者说时动态绑定,好处是对外提供统一接口,但是具体实现类却千变万化,妙呀!)

public class FutureTask<V> implements RunnableFuture<V> {
    
    //构造函数
    public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       
    }

    //run方法
    //关键代码:
    //1.result = c.call(),可以看到run方法调用了call()方法
    //2.set(result),可以看到运行结果通过set方法保存
    public void run() {
        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;
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }
    
    //get方法
    //调用report方法返回结果,具体看report方法
    public V get() throws InterruptedException, ExecutionException {
        int s = state;
        if (s <= COMPLETING)
            s = awaitDone(false, 0L);
        return report(s);
    }

    //set方法
    //关键代码:
    //outcome = v;可以看到,结果包存到了outcome中
    protected void set(V v) {
        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
            outcome = v;
            UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
            finishCompletion();
        }
    }

    //report方法
    //关键代码:
    //Object x = outcome,return (V)x;可以看到,结果outcome赋给x然后返回了
    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);
    }
}

4.3 RunnableFuture接口 ---继承了Runnable,Future接口

public interface RunnableFuture<V> extends Runnable, Future<V> {
    
    void run();
}

4.4 Runnable接口 

@FunctionalInterface
public interface Runnable {
    
    public abstract void run();
}

4.5 Future接口 

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;
}

5. 为了能站在全局的角度来看,画了一张流程图。

感觉好丑。。。可能只有我自己能看懂。。。

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值