Callable和Future浅析

从java5开始,java提供了Callable接口,Callable接口提供了一个call方法可以作为线程的执行体,但call方法比run方法功能更加强大。主要体现在:

1.call方法可以有返回值;

2.call方法可以声明抛出异常。

因此我们完全可以提供一个Callable对象作为Thread的target,而该线程的线程执行体就是该Callable对象的call方法,问题是:Callable接口是java5新增的接口,而且它并没有继承Runnable接口,所以Callable接口不可以直接作为Thread的target,而且call方法还有一个返回值,那么我们如何获取call方法的返回值呢?java5提供了Future接口代表Callable接口里call方法的返回值,FutureTask是Future的实现类,FutureTask实现了Runnable接口,所以创建线程时,可以将FutureTask传入,另外,FutureTask创建时需要一个Callable参数,所以这样一来,Callable就和Thread挂钩了,Thread实际执行的是Callable的call方法,而其返回值由FutureTask获取,调用其get方法即可获得返回值。

示例代码:

Callable<Integer> c = new Callable<Integer>()
		{
			@Override
			public Integer call() throws Exception
			{
				System.out.println("running...");
				Thread.sleep(2000);
				return 215;
			}
		};
		FutureTask<Integer> task = new FutureTask<>(c);
		new Thread(task).start();
		try
		{
			System.out.println("result  : "+task.get());
		}
		catch (InterruptedException e)
		{
			e.printStackTrace();
		}
		catch (ExecutionException e)
		{
			e.printStackTrace();
		}
	}

上面说到可以调用FutureTask方法获取call的返回值,那么如果call方法是个耗时操作,调用get方法的线程岂不是得一直等着call结束么?恩,确实是这样。调用get方法的线程会阻塞

下面从源码角度简单分析下Callable和Future:

Callable方法没啥好说的,只有一个call方法,作为线程的执行体

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

FutureTask类实现了RunnableFuture接口,而RunnableFuture继承了Runnable和Future接口:

Runnable接口大家都很熟悉,那么这个Future接口提供了什么样的方法呢?

public interface Future<V> {
    boolean cancel(boolean mayInterruptIfRunning);//取消Future里面关联的call方法
    boolean isCancelled();//任务是否取消
    boolean isDone();//任务是否完成
    V get() throws InterruptedException, ExecutionException;//获取call方法的结果
    V get(long timeout, TimeUnit unit)//设置超时时间,超过此时间未收到结果将抛出异常
        throws InterruptedException, ExecutionException, TimeoutException;
}

我们都知道,当Thread被start之后,会调用Thread的run方法,而Thread的run方法逻辑如下:

 @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }

即判断是否传入了Runnable类型的target,如果有,将会执行Runnable的run方法,这里我们传入的是FutureTask,所以会调用FutureTask类的run方法:

  public void run() {
        sync.innerRun();
    }

只有一行代码,调用了sync类的innerRun方法,sync为FutureTask的内部类,我们继续追踪此方法的实现:

void innerRun() {
            if (!compareAndSetState(READY, RUNNING))
                return;
            runner = Thread.currentThread();
            if (getState() == RUNNING) { // recheck after setting thread
                V result;
                try {
                    result = callable.call();//调用的是callable的call方法
                } catch (Throwable ex) {
                    setException(ex);
                    return;
                }
                set(result);
            } else {
                releaseShared(0); // cancel
            }
        }

innerRun方法中果然还是调用了callable的call方法,并将结果赋给result变量。

再看FutureTask的get方法:

public V get() throws InterruptedException, ExecutionException {
        return sync.innerGet();
    }

调用的是sync的innerGet方法:

 V innerGet() throws InterruptedException, ExecutionException {
            acquireSharedInterruptibly(0);
            if (getState() == CANCELLED)
                throw new CancellationException();
            if (exception != null)
                throw new ExecutionException(exception);
            return result;
        }

返回了result变量。

时间: 2024-11-05 06:05:49

Callable和Future浅析的相关文章

Callable、Future和FutureTask浅析

我们知道创建线程的方式有两种,一种是实现Runnable接口,另一种是继承Thread,但是这两种方式都有个缺点,那就是在任务执行完成之后无法获取返回结果,那如果我们想要获取返回结果该如何实现呢?还记上一篇Executor框架结构中提到的Callable接口和Future接口吗?,是的,从JAVA SE 5.0开始引入了Callable和Future,通过它们构建的线程,在任务执行完成后就可以获取执行结果,今天我们就来聊聊线程创建的第三种方式,那就是实现Callable接口. 1.Callabl

Java多线程编程:Callable、Future和FutureTask浅析

通过前面几篇的学习,我们知道创建线程的方式有两种,一种是实现Runnable接口,另一种是继承Thread,但是这两种方式都有个缺点,那就是在任务执行完成之后无法获取返回结果,那如果我们想要获取返回结果该如何实现呢?还记上一篇Executor框架结构中提到的Callable接口和Future接口吗?,是的,从Java SE 5.0开始引入了Callable和Future,通过它们构建的线程,在任务执行完成后就可以获取执行结果,今天我们就来聊聊线程创建的第三种方式,那就是实现Callable接口.

Java并发编程:Callable、Future和FutureTask(转)

Java并发编程:Callable.Future和FutureTask 在前面的文章中我们讲述了创建线程的2种方式,一种是直接继承Thread,另外一种就是实现Runnable接口. 这2种方式都有一个缺陷就是:在执行完任务之后无法获取执行结果. 如果需要获取执行结果,就必须通过共享变量或者使用线程通信的方式来达到效果,这样使用起来就比较麻烦. 而自从Java 1.5开始,就提供了Callable和Future,通过它们可以在任务执行完毕之后得到任务执行结果. 今天我们就来讨论一下Callabl

【转】Java线程系列:Callable和Future

一.前言 在研究JDK1.8的CompletableFuture时,顺道将Futrue一起扫了盲~这篇博文纯转载 二.正文 本篇说明的是Callable和Future,它俩很有意思的,一个产生结果,一个拿到结果.        Callable接口类似于Runnable,从名字就可以看出来了,但是Runnable不会返回结果,并且无法抛出返回结果的异常,而Callable功能更强大一些,被线程执行后,可以返回值,这个返回值可以被Future拿到,也就是说,Future可以拿到异步执行任务的返回值

Callable, Runnable, Future, FutureTask

Java并发编程之Callable, Runnable, Future, FutureTask Java中存在Callable, Runnable, Future, FutureTask这几个与线程相关的类或接口, 下面来了解一下它们的作用和区别. 一.Callable和Runnable Callable和Runnable类似, 实现Callable和Runnable接口的类都是可以被其他线程运行的任务, Callable和Runnable主要有以下几点区别: (1). Callable中声明的

Callable、Future和FutureTask

Runnable是执行工作的独立任务,但是它不返回任何值,如果需要获取执行结果,就必须通过共享变量或者使用线程通信的方式来达到效果,这样使用起来就比较麻烦.自从Java 1.5开始,就提供了Callable和Future,通过它们可以在任务执行完毕之后得到任务执行结果. 一.Runnable java.lang.Runnable是一个接口,在它里面只声明了一个run()方法: 由于run()方法返回值为void类型,所以在执行完任务之后无法返回任何结果. 二.Callable Callable位

Java多线程21:多线程下的其他组件之CyclicBarrier、Callable、Future和FutureTask

CyclicBarrier 接着讲多线程下的其他组件,第一个要讲的就是CyclicBarrier.CyclicBarrier从字面理解是指循环屏障,它可以协同多个线程,让多个线程在这个屏障前等待,直到所有线程都达到了这个屏障时,再一起继续执行后面的动作.看一下CyclicBarrier的使用实例: public static class CyclicBarrierThread extends Thread { private CyclicBarrier cb; private int sleep

[转载] Java并发编程:Callable、Future和FutureTask

转载自http://www.cnblogs.com/dolphin0520/p/3949310.html 在前面的文章中我们讲述了创建线程的2种方式,一种是直接继承Thread,另外一种就是实现Runnable接口. 这2种方式都有一个缺陷就是:在执行完任务之后无法获取执行结果. 如果需要获取执行结果,就必须通过共享变量或者使用线程通信的方式来达到效果,这样使用起来就比较麻烦. 而自从Java 1.5开始,就提供了Callable和Future,通过它们可以在任务执行完毕之后得到任务执行结果.

Callable与Future的介绍

Callable与 Future 两功能是Java在后续版本中为了适应多并发才加入的,Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其他线程执行的任务. Callable的接口定义如下: public interface Callable<V> { V call() throws Exception; } Callable和Runnable的区别如下: I    Callable定义的方法是call,而Runnable定义的方法是