CallableFuture

Callable & Future

Executors本身提供了一种对于多线程的封装,而Executor还支持另一种类型的任务:Callable。Callables也是类似于Runnable的函数接口,不同之处在于,Callable返回一个值Future,用来描述一个异步计算的结果。Callable接口本身是一个Lambda表达式(函数式接口)

Callable<Integer> task = () -> {
    try {
        TimeUnit.SECONDS.sleep(1);
        return 123;
    }
    catch (InterruptedException e)
        throw new IllegalStateException("task interrupted", e);
    }
};

Callbale也可以像Runnable一样提交给executor services。但是submit()不会等待任务完成,executor service不能直接返回callable的结果。不过,executor可以返回一个Future类型的结果,它可以用来在稍后某个时间取出实际的结果。

ExecutorService executor = Executors.newFixedThreadPool(1);
Future<Integer> future = executor.submit(task);

System.out.println("future done? " + future.isDone());

Integer result = future.get();

System.out.println("future done? " + future.isDone());
System.out.print("result: " + result);

Future与底层的ExecutorService紧密的结合在一起。记住,如果你关闭executor,所有的未中止的future都会抛出异常。

executor.shutdownNow();
future.get();

任何future.get()调用都会阻塞,然后等待直到callable中止。在最糟糕的情况下,一个callable持续运行——因此使你的程序将没有响应。我们可以简单的传入一个时长来避免这种情况。

ExecutorService executor = Executors.newFixedThreadPool(1);

Future<Integer> future = executor.submit(() -> {
    try {
        TimeUnit.SECONDS.sleep(2);
        return 123;
    }
    catch (InterruptedException e) {
        throw new IllegalStateException("task interrupted", e);
    }
});

future.get(1, TimeUnit.SECONDS);

运行上面的代码将会产生一个TimeoutException

Exception in thread "main" java.util.concurrent.TimeoutException
    at java.util.concurrent.FutureTask.get(FutureTask.java:205)
下一页