天天看点

Java多线程--Future与Callable

Callable

Callable与Runnable类似,但是执行任务后能返回结果;Future接口表示异步任务,它能拿到Callable的返回值,即获取结果。

Callable接口如下:

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

这是一个泛型接口,返回的类型就是传递进来的类型,或者抛出异常。

使用: 一般作为参数,详见后面的例子

Future

Future能具体的Runnable或者Callable任务的执行进行取消、查询是否完成、获取结果。

接口如下:

public interface Future<V> {
    // 取消对此任务的执行
    boolean  cancel(boolean mayInterruptIfRunning);
    // 如果在任务正常完成前将其取消,则返回 true
    boolean  isCancelled(); 
    // 如果任务已完成返回 true
    boolean  isDone(); 
    // 获取执行结果,该方法会阻塞一直等到任务执行完成
    V  get() throws InterruptedException, ExecutionException; 
    // 最多等待为使计算完成所给定的时间之后,获取其结果,如果超时,结果返回null
    V  get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}
           

Future的实现类:FutureTask

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

可以看到,FutureTask实现了Runnable和Future,既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值。

FutureTask的两个构造方法:

public FutureTask(Callable<V> 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
    }
           

示例如下

使用场景:当前线程(线程A)需要依赖于另一个线程(线程B)的处理结果,而线程B处理结果需要一定的时间,Future模式就可以让线程A的数据请求交给B,需要数据时再去get。而在B处理时A还能处理其他业务。

package com.learn;

import java.util.concurrent.Callable;

public class FooCallable implements Callable<String> {
    private String name;

    public FooCallable(String name) {
        this.name = name;
    }

    @Override
    public String call() throws Exception {
        System.out.println("Task任务执行");
        Thread.sleep();
        return name;
    }

}
package com.learn;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;

public class FutureTaskTest {

    public static void main(String[] args) {
        FooCallable a = new FooCallable("A");
        FutureTask<String> futureTask1 = new FutureTask<>(a);
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.submit(futureTask1);

        System.out.println("主线程执行任务");
        try {
            if (!futureTask1.isDone()) { // 任务没有完成,会等待,直到任务完成
                System.out.println("FutureTask执行结果" + futureTask1.get());
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        executorService.shutdown();
        System.out.println("All执行完毕");
    }

}
           

执行结果:

Task任务执行
主线程执行任务
FutureTask执行结果A
All执行完毕
           

示例2

采用submit(Callable)

package com.learn;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class FutureTaskTest {

    public static void main(String[] args) {
        FooCallable a = new FooCallable("A");
        ExecutorService executorService = Executors.newCachedThreadPool();
        Future<String> ret = executorService.submit(a);

        System.out.println("主线程执行任务");
        try {
            System.out.println("Task执行结果" + ret.get());
        } catch (Exception e) {
            e.printStackTrace();
        }
        executorService.shutdown();
        System.out.println("All执行完毕");
    }

}