Java并发:理解callable futuretask runnable thread

创建线程,可以直接extends thread类,在run方法中指定线程要执行的操作。

那还要runnable干什么呢?

因为java不支持多继承,只能继承一个类,如果继承了thread,就不能继承其他类了,这样不够灵活,不方便扩展。
而java支持实现多个接口,于是提供了一个runnable接口,接口中只有一个void run方法。

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

通过实现runnable接口的run方法,使类具有了run的能力。再使用new thread(runnable)构造方法,把runnable送入thread执行。

//创建一个Runnable任务对象,RunnableTask实现了run方法
RunnableTask rt = new RunnableTask();

//将实现的Runnable类的实例传入thread构造函数
Thread thread=new Thread(rt);
thread.start();

实际上,thread本身也是继承了runnable接口,获取了run的能力,继承thread相当于实现了runnable。

那为什么又来了一个callable呢?

因为我们有时想要获取线程的执行结果。

thread和runnable可以通过run把任务送入线程,但是并且run方法被void修饰,没有返回值,也没提供获取执行结果的其他方法。

于是callable接口来啦,它里面只有一个V call方法。子类可以自定义call方法的返回值类型,使用return将结果返回。

public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     * 计算得到结果,如果无法计算就抛出异常
     */
    V call() throws Exception;
}

>.<,那怎么使用callable呢,futureTask又是什么鬼?

细细观察thread构造方法,发现有传入runnable的构造方法,但是没有直接传入callable的构造方法。

那怎么办呢,callable的call方法已经写好了任务,还能返回结果,如何把callable送入线程执行呢。
答:把callable装到runnable里面,再送入thread。这里的futureTask就是一种runnable对象,用来装callable。

futureTask实现了runnable和future接口,具有run的能力,而future接口就提供了get执行结果的能力。

// 创建Callable接口任务,CallableTask里面实现了call方法
CallableTask task = new CallableTask();

// 把Callable包装成runnable,即FutureTask类
FutureTask<Integer> futureTask = new FutureTask<>(task);

//把runnable送入thread执行
new Thread(futureTask).start();

// 使用future接口提供的get方法,获取线程执行结果
System.out.println(futureTask.get());

futureTask为什么还支持传入runnable,runnable不是应该直接传给thread吗,为什么还要放入futureTask然后再传给thread?

从thread视角看,runnable不直接到碗里来,反而先变成一个callable,然后又被futureTask包起来变成一个runnable,最后再进入thread。这不是多此一举吗?

我想,应该是为了获得返回结果的能力。比如我已经使用runnable写好了run方法,它已经在很多地方使用,如何才能不修改代码也能让它获取到执行结果呢。
futureTask支持传入runnable,其内部会把runable转换为callable,这样runnable就获得了get结果的方法,然后原始runnable就伪装成callable被futureTask带进thread。

如果任务执行成功的话,就会返回传入的result。如果不需要返回值的话可以传入一个null。

public FutureTask(Runnable runnable, V result) {
    this.callable = Executors.callable(runnable, result);
    this.state = NEW;       // ensure visibility of callable
}

java.util.concurrent.Executors里面提供了适配器方法把runnable转换为callable。

/**
 * java.util.concurrent.Executors.java
 */
 //传入Runnable和装结果的result,就能返回一个Callable
public static <T> Callable<T> callable(Runnable task, T result) {
    if (task == null)
        throw new NullPointerException();
    return new RunnableAdapter<T>(task, result);
}

//真正执行转换的类,RunnableAdapter是一种Callable类
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;
    }
    //runnable的run方法被包进Callable的call方法中
    public T call() {
        task.run();
        return result;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值