第一部门:What
在Java中一般通过担任Thread类可能实现Runnable接口这两种方法来建设多线程,可是这两种方法都有个缺陷,就是不能在执行完成后获取执行的功效,因此Java 1.5之后提供了Callable和Future接口,通过它们就可以在任务执行完毕之后获得任务的执行功效。本文会扼要的先容利用要领,然后会从源代码角度阐明下详细的实现道理。
本文以Java 1.7的代码举办阐明。
第二部门:How
Callable接口
对付需要执行的任务需要实现Callable接口,Callable接口界说如下:
public interface Callable<V> { /** * 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; }
可以看到Callable是个泛型接口,泛型V就是要call()要领返回的范例。Callable接口和Runnable接口很像,都可以被别的一个线程执行,可是正如前面所说的,Runnable不会返回数据也不能抛出异常。
Future接口
Future接口代表异步计较的功效,通过Future接口提供的要领可以查察异步计较是否执行完成,可能期待执行功效并获取执行功效,同时还可以打消执行。Future接口的界说如下:
public interface Future<V> { boolean cancel(boolean mayInterruptIfRunning); boolean isCancelled(); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }
FutureTask
Future只是一个接口,不能直接用来建设工具,FutureTask是Future的实现类,
FutureTask的担任图如下:
可以看到,FutureTask实现了RunnableFuture接口,则RunnableFuture接口担任了Runnable接口和Future接口,所以FutureTask既能当做一个Runnable直接被Thread执行,也能作为Future用来获得Callable的计较功效。
利用
FutureTask一般共同ExecutorService来利用,也可以直接通过Thread来利用。
package com.beautyboss.slogen.callback; import java.util.concurrent.*; /** * Author : Slogen * AddTime : 17/6/4 * Email : huangjian13@meituan.com */ public class CallDemo { public static void main(String[] args) throws ExecutionException, InterruptedException { /** * 第一种方法:Future + ExecutorService * Task task = new Task(); * ExecutorService service = Executors.newCachedThreadPool(); * Future<Integer> future = service.submit(task1); * service.shutdown(); */ /** * 第二种方法: FutureTask + ExecutorService * ExecutorService executor = Executors.newCachedThreadPool(); * Task task = new Task(); * FutureTask<Integer> futureTask = new FutureTask<Integer>(task); * executor.submit(futureTask); * executor.shutdown(); */ /** * 第三种方法:FutureTask + Thread */ // 2. 新建FutureTask,需要一个实现了Callable接口的类的实例作为结构函数参数 FutureTask<Integer> futureTask = new FutureTask<Integer>(new Task()); // 3. 新建Thread工具并启动 Thread thread = new Thread(futureTask); thread.setName("Task thread"); thread.start(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Thread [" + Thread.currentThread().getName() + "] is running"); // 4. 挪用isDone()判定任务是否竣事 if(!futureTask.isDone()) { System.out.println("Task is not done"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } int result = 0; try { // 5. 挪用get()要领获取任务功效,假如任务没有执行完成则阻塞期待 result = futureTask.get(); } catch (Exception e) { e.printStackTrace(); } System.out.println("result is " + result); } // 1. 担任Callable接口,实现call()要领,泛型参数为要返回的范例 static class Task implements Callable<Integer> { @Override public Integer call() throws Exception { System.out.println("Thread [" + Thread.currentThread().getName() + "] is running"); int result = 0; for(int i = 0; i < 100;++i) { result += i; } Thread.sleep(3000); return result; } } }
第三部门:Why
结构函数