java并发编程系列之Callable与Future的应用

在我们传统的观念中,创建线程无非就两种方式:1、直接new 一个Thread;2、实现Runnable,其实这两种方式的实质是一样的,有一个共同的特点:无返回值,并且无法抛出返回结果的异常,顺便我们讲一下其他的线程创建方式。那我们想拿到线程的返回值,怎么做了?我们可以使用java并发包中的Callable和Future来实现。下面就来分享一下实现方式。

1、Callable接口

Callable接口的原型如下:

[java] view plain copy
  1. public interface Callable<V> {  
  2.     V call() throws Exception;  
  3. }  

这个接口设计之初有两个目的:1、解决任务有返回的问题;2、解决任务抛异常的问题,该接口只定义了一个方法,就是call,其实Callable接口和Runnable接口很类似,都是设计用来执行多线程的,唯一的不同就是Runnable没有返回值和抛异常。

1、Future接口

Future接口的原型如下:

[java] view plain copy
  1. public interface Future<V> {  
  2. // 试图取消一个执行的任务,如果该任务已经执行完毕,或者已经取消,或者是一些无法取消的原因,则返回false,正常取消则返回true,如果成功取消,则这个任务不会启动,如果当前任务正在执行,且mayInterruptIfRunning设置为true,则正在执行的任务会被中断,此时,如果调用isCancelled和isDone方法来判断当前任务是否执行完,或者是是否取消,则会返回true  
  3. boolean cancel(boolean mayInterruptIfRunning);  
  4. // 判断任务是否被取消  
  5. boolean isCancelled();  
  6. // 判断任务是否已经完成  
  7. boolean isDone();  
  8. // 获取返回值,等待任务执行完成后,对返回结果进行一个检索,否则就会阻塞,知道任务转成执行完成状态  
  9. V get() throws InterruptedException, ExecutionException;  
  10. // 获取返回值,会在等待最大的给定时间后,对返回结果进行一个检索,否则抛对应的异常,而不会一直阻塞  
  11.     V get(long timeout, TimeUnit unit)  
  12.         throws InterruptedException, ExecutionException, TimeoutException;  
  13. }  

1、使用示例

看完了这两个接口的定义和含义,下面我们做一个简单的示例,方便大家理解。

3.1 单个返回结果的示例

代码如下:

[java] view plain copy
  1. public void demo(){  
  2.         /* 
  3.          *  创建线程,这种线程的创建方式也是jdk1.5提供的,是java推荐的方式,如果对这种方式感兴趣 
  4.          *  可以看我之前写的一篇博客<a href="http://blog.csdn.net/liuchuanhong1/article/details/52042182">http://blog.csdn.net/liuchuanhong1/article/details/52042182</a> 
  5.          *  以下是创建一个单一线程的线程池 
  6.          */  
  7.         ExecutorService service = Executors.newSingleThreadExecutor();  
  8.         // 注意,此处需用submit来提交任务,这样才会有返回值,如果使用Execute来提交任务,则无返回值  
  9.         Future<String> result = service.submit(new Callable<String>() {  
  10.             public String call() throws Exception {  
  11.                 // 可能需要处理的业务逻辑  
  12.                 Thread.sleep(2000);  
  13.                 // 返回业务逻辑处理的结果  
  14.                 return "chhliu";  
  15.             }  
  16.         });  
  17.         try {  
  18.             Thread.sleep(2000);  
  19.             String resultStr = result.get();  
  20.             System.out.println("the result is: "+resultStr);  
  21.         } catch (InterruptedException e) {  
  22.             e.printStackTrace();  
  23.         } catch (ExecutionException e) {  
  24.             e.printStackTrace();  
  25.         }  
  26.     }  

测试类及测试结果如下:

the result is: chhliu

从测试结果可以看出,我们是拿到了任务的返回结果的。

3.2 多个返回结果的示例

代码如下:

[java] view plain copy
  1. /** 
  2.      * 描述:多返回值的示例 
  3.      * void 
  4.      */  
  5.     public List<Future<String>> demo1(){  
  6.         // 创建多个线程  
  7.         ExecutorService service = Executors.newCachedThreadPool();  
  8.         List<Future<String>> list = new ArrayList<Future<String>>();  
  9.         for(int i=0; i<10; i++){  
  10.             Future<String> result = service.submit(new Callable<String>() {  
  11.                 @Override  
  12.                 public String call() throws Exception {  
  13.                         return Thread.currentThread().getName();  
  14.                 }  
  15.             });  
  16.             list.add(result);  
  17.         }  
  18.         return list;  
  19.     }  
  20.       
  21.     /** 
  22.      * 描述:多返回值的示例,另一种实现方式 
  23.      * @author chhliu 
  24.      * void 
  25.      */  
  26.     public CompletionService<String> demo2(){  
  27.         // 创建多个线程  
  28.         ExecutorService service = Executors.newCachedThreadPool();  
  29.         CompletionService<String> completion = new ExecutorCompletionService<String>(service);  
  30.         for(int i=0; i<10; i++){  
  31.             completion.submit(new Callable<String>() {  
  32.                 @Override  
  33.                 public String call() throws Exception {  
  34.                         return Thread.currentThread().getName();  
  35.                 }  
  36.             });  
  37.         }  
  38.         return completion;  
  39.     }  

上面是两种方式实现的多返回值的使用示例,测试结果如下:

[java] view plain copy
  1. the current thread name is: pool-1-thread-1  
  2. the current thread name is: pool-1-thread-2  
  3. the current thread name is: pool-1-thread-2  
  4. the current thread name is: pool-1-thread-2  
  5. the current thread name is: pool-1-thread-2  
  6. the current thread name is: pool-1-thread-4  
  7. the current thread name is: pool-1-thread-6  
  8. the current thread name is: pool-1-thread-3  
  9. the current thread name is: pool-1-thread-1  
  10. the current thread name is: pool-1-thread-5  

从上面的测试结果中,我们不难看出,任务的返回结果我们都拿到了,拿到这个返回结果之后,我们就可以对这些结果做进一步的处理。

其实,在jdk1.5中,还为我们提供了另外一个类,来实现上面的功能,就是FutureTask,这个类的原型如下:

[java] view plain copy
  1. public class FutureTask<V> implements RunnableFuture<V>  
  2.   
  3. public interface RunnableFuture<V> extends Runnable, Future<V>  

从上面的类实现和继承关系上来看,FutureTask类实现了Runnable和Future这两个接口,所以说,这个类兼顾了两者的优点,我们在使用的时候,既可以通过Executors,也可以通过Thread来使用,如果在主线程中需要执行比较耗时的操作时,但又不想阻塞主线程时,可以把这些作业交给Future对象在后台完成,当主线程将来需要时,就可以通过Future对象获得后台作业的计算结果或者执行状态。下面,我们就用FutureTask类,实现上面示例1,代码如下:

[java] view plain copy
  1. /** 
  2.      * 描述:使用FutureTask来实现上面的示例 
  3.      */  
  4.     public String demo3() throws InterruptedException, ExecutionException{  
  5.         Callable<String> call = new Callable<String>() {  
  6.             @Override  
  7.             public String call() throws Exception {  
  8.                 return "chhliu";  
  9.             }  
  10.         };  
  11.         FutureTask<String> task = new FutureTask<String>(call);  
  12.         ExecutorService service = Executors.newSingleThreadExecutor();  
  13.         service.submit(task);  
  14.         return task.get();  
  15.     }  

测试结果如下:

the result is: chhliu

也就是说,我们同样拿到了任务的返回结果。

关于Callable和Future的内容,我们就讲到这里
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值