java中Callable、Future、FutureTask讲解与实战

#博学谷IT学习技术支持#

一:Callable

Callable是类似Thread和Runnable,也是一种创建线程的方式,只不过Callable创建的线程可以带返回值。

可以看下Callable的源码如下:


@FunctionalInterface
public interface Callable {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

可以看到它的返回值就是传入的V值

使用方法如下:

static class TestA implements Callable {
    @Override
    public String call() throws Exception {
        return "我是一个带返回值的线程";
    }
}

这里先不说怎么调用它,放在下面讲Future和FutureTask的时候一起说

二:Future

Future是对具体的线程的执行结果进行取消、查询是否完成、获取结果。

如Runnable、Callable线程。

我们可以看下Future的源码,注释部分我给删除了,想看的自行看源码去


public interface Future {
    boolean cancel(boolean mayInterruptIfRunning);
    boolean isCancelled();
    boolean isDone();
    V get() throws InterruptedException, ExecutionException;
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

cancel(boolean mayInterruptRunning) 方法

1.用来取消线程,如果取消成功则返回true,取消失败则返回false。

2.mayInterruptIfRunning参数是否允许取消正在执行却没有执行完毕的任务。

3.如果任务已经完成无论mayInterruptIfRunning设置的是true还是false,都返回false。

4.取消进行中任务mayInterruptIfRunning设置为true 返回true。

5.取消进行中任务mayInterruptIfRunning设置为false返回false。

6.如果任务还未执行不管mayInterruptIfRunning设置的是true还是false,都返回true。

isCancelled方法

1.判断当前任务是否取消成功,如果在任务正常完成前被取消成功,则返回 true。

isDone方法

1.表示任务是否已经完成,若任务完成,则返回true。

get方法

1.用来获取任务执行结果,这个方法会产生阻塞,会等到任务完成后才会返回,慎用。

2.相当于ABC三行代码,A是线程任务,B是get方法获取该线程返回值,如果A线程一直没有完成,B这里会一直阻塞,导致C没法执行。

get(long timeout, TimeUnit unit)方法

1.跟上面的get方法一样都是获取任务执行结果,只不过这个可以设置超时时间,超过时间没有返回直接返回null

总结Future有三个功能:判断任务是否完成,取消任务,获取任务结果。

下面是实战代码:

public static void main(String[] args) throws ExecutionException, InterruptedException {
    System.out.println("主线程开始执行");
    TestA a = new TestA();
    // 这里说一下一般Callable都是配合线程池一起使用,这里是手动new了一个newCachedThreadPool()的无参数线程池
    // 不懂的的可以自行百度线程池使用方式
    ExecutorService executorService = Executors.newCachedThreadPool();
    Future executors = executorService.submit(a);
    // get方法
    System.out.println(executors.get());
    // 判断线程是否完成
    System.out.println(executors.isDone());
    // 关闭线程池
    executorService.shutdown();
    System.out.println("主线程执行完成");
}

static class TestA implements Callable {
    @Override
    public String call() throws Exception {
        Thread.sleep(1000);
        return "我是一个带返回值的线程";
    }
}

返回结果如下:


主线程开始执行
我是一个带返回值的线程
true
主线程执行完成

三:FutureTask

我们先看下FutureTask源码


public class FutureTask implements RunnableFuture
public interface RunnableFuture extends Runnable, Future

1.它是实现了RunnableFuture接口,然后RunnableFuture继承了Runnable和Future

2.所以TutureTask可以作为Runnable被执行,也能作为Future得到Callable的返回值

3.RunnableFuture提供了2个构造器我也是从源码复制出来的,如下:


public FutureTask(Callable callable) {
    if (callable == null)
        throw new NullPointerException();
    this.callable = callable;
    this.state = NEW;       // ensure visibility of callable
}
public FutureTask(Runnable runnable, V result) {
    this.callable = Executors.callable(runnable, result);
    this.state = NEW;       // ensure visibility of callable
}

4.它里面也提供了一系列跟Future一样的get、isDone等的方法。

5.FutureTask用法,直接看代码吧


public static void main(String[] args) throws ExecutionException, InterruptedException {
    System.out.println("主线程开始执行");
    // 这里还是用下线程池
    ExecutorService executorService = Executors.newCachedThreadPool();
    TestA a = new TestA();
    FutureTask task = new FutureTask(a);
    executorService.submit(task);
    // 把FutureTask当成Runnable去执行,这个实现方式是跟上面一样的,只不过用的是Thread
    /*Thread thread = new Thread(task);
    thread.start();*/
    // get方法
    System.out.println(task.get());
    // 判断线程是否完成
    System.out.println(task.isDone());
    // 关闭线程池
    executorService.shutdown();
    //这里在提一下上面submit是有返回值的,这里就不多说有兴趣的可以自己去看
    System.out.println("主线程执行完成");
}

static class TestA implements Callable {
    @Override
    public String call() throws Exception {
        Thread.sleep(1000);
        return "我是一个带返回值的线程2";
    }
}

运行结果如下:


主线程开始执行
我是一个带返回值的线程2
true
主线程执行完成

好了到这里Callable、Future、FutureTask也介绍完了,看完的你应该也掌握了基本的用法了,如哪里讲的不好还望指出,喜欢的可以关注作者。

你可能感兴趣的:(java,java)