通过实现Callable和Runnable接口都能够创建线程的执行体,但是Runnable接口并不返回任何值,如果你希望任务在完成的时候能够返回一个值
那么就可以通过实现Callable接口来实现。在JavaAPI中是这样描述Callable接口的:Callable和Runnable相似,他们的类实例都能够被其他Thread
执行,但是Callable接口能够返回一个值或者抛出一个异常,Runnable却不能,实现Callable接口需要重写其唯一的call()方法。
Callable接口是java 5新增加的接口,java5定义了Callable接口中的call()方法的返回类型为Future接口类型,并且java5为Future接口提供一个实现
类FutureTask,FutureTask 还实现了Runnable接口,由于Thread的执行体只接受Runnable接口实例,所以如果想Callable实例作为Thread的执行
体就必须通过FureTask来作为桥梁,即:正常情况下我们是将一个Runable接口实例设置进去(在这里这个实例即是FutureTask对象,因为
FutureTask实现了Runable接口,FutureTask对象即是Runnable接口的一个实例,而Callable接口实例的类型是Future类型,而FutureTask实现了
Future接口,所以Callable接口实例即相当于FutureTask实例:ps:其实不是,但是可以这样理解),下面看Callable接口实例作为Thread的执行体
的实现。
public class MyThread implements Callable<String>{ @Override public String call() throws Exception { String str = "史蒂芬森电话"; System.out.println(str); return str; } public static void main(String[] args) { MyThread callable = new MyThread();//创建Callable接口实例 FutureTask<String> futureTask = new FutureTask<>(callable); new Thread(futureTask).start(); //其实就三步:1 创建Callable实例 //2将Callable实例设置进FutureTask实例中 //3将FutureTask实例作为Runnable类型设置进Thread中 try { System.out.println("子线程的返回结果:"+futureTask.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } }
运行结果:
下面还介绍一种不通过FutureTask,来实现Callable实例作为线程的执行体
public class MyThread implements Callable<String>{ int num; public MyThread(int num){ this.num = num; } @Override public String call() throws Exception { System.out.println(num); return "this task num is "+num; } public static void main(String[] args) { ExecutorService exec = Executors.newCachedThreadPool(); List<Future<String>> list = new ArrayList<Future<String>>(); for (int i = 0; i < 10; i++) { MyThread callable = new MyThread(i);//创建Callable接口实例 list.add(exec.submit(callable));//将callable接口实例提交进线程池 } for (Future<String>fs:list) { try { System.out.println(fs.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } exec.shutdown(); } }
执行结果:
在这里还要注意一下,如果你将 exec.shutdown()注释掉,所有线程执行完毕,但是主线程还还没结束,这是因为线程池还没有关闭,导致主线程
无法结束,如果不注释掉,所有的线程执行完毕后,主线程也就自然结束了。
在上面的代码里我们会看到submit()方法会产生一个Future对象,你可以使用isDone方法来检查Future是否完成,当任务完成时,它会返回一个结果
你可以调用get()方法来获取该结果,如果任务还未完成就调用get()方法时,get()方法将阻塞,直至任务完成。
参考链接:http://www.cnblogs.com/liubingna/p/3401403.html