Callable,Runnable比较及用法

本文深入探讨多线程编程中Callable和Future的使用,包括它们的区别、实现方式以及如何通过Future获取异步计算结果。重点介绍了Future模式在请求与响应过程中的应用,以及通过ExecutorService实现线程池来创建线程的步骤。
摘要由CSDN通过智能技术生成
编写多线程程序一般有三种方法,Thread,Runnable,Callable.

Runnable和Callable的区别是,
(1)Callable规定的方法是call(),Runnable规定的方法是run().
(2)Callable的任务执行后可返回值,而Runnable的任务是不能返回值得
(3)call方法可以抛出异常,run方法不可以

(4)运行Callable任务可以拿到一个Future对象,Future 表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。计算完成后只能使用 get 方法来获取结果,如果线程没有执行完,Future.get()方法可能会阻塞当前线程的执行;如果线程出现异常,Future.get()会throws InterruptedException或者ExecutionException;如果线程已经取消,会跑出CancellationException。取消由cancel 方法来执行。isDone确定任务是正常完成还是被取消了。一旦计算完成,就不能再取消计算。如果为了可取消性而使用 Future 但又不提供可用的结果,则可以声明Future<?> 形式类型、并返回 null 作为底层任务的结果。Future接口的定义如下:


Future模式
Future模式在请求发生时,会先产生一个Future凭证给发出请求的客户,它的作用就像是Proxy物件,同时,由一个新的执行线程持续进行目标物件的生成(Thread-Per-Message),真正的目标物件生成之后,将之设定至Future之中,而当客户端真正需要目标物件时,目标物件也已经准备好,可以让客户提取使用。
结合JDK的Future来看,就是你run线程后,你可以把线程的返回值赋给Future并返回一个Future对象。这时你可以立即拿到这个对象,然后进行下面的逻辑。但是如果你要get这个Future中的线程结果,就会被阻塞直到线程结束。
就相当于现在的期房,你把手续和钱都交上去了,就可以马上拿到合同,但只有合同没有房子。这个时候你已经是有房一族了,你可以先去买家电买装修(走下面的其他逻辑)。但是你要把家电和装修放进去,就必须等到房子完工(阻塞)。


               
public interface Future<T>
{
    V get() throws ...;
    V get(long timeout, TimeUnit unit) throws ...;
    void cancle(boolean mayInterrupt);
    boolean isCancelled();
    boolean isDone();
}
具体的实现类为java.util.concurrent.FutureTask<V>。


1、通过实现Callable接口来创建Thread线程:


其中,Callable接口(也只有一个方法)定义如下:


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

步骤1:创建实现Callable接口的类SomeCallable<Integer>;


步骤2:创建一个类对象:


      Callable<Integer> oneCallable = new SomeCallable<Integer>();
 
步骤3:由Callable<Integer>创建一个FutureTask<Integer>对象:


      FutureTask<Integer> oneTask = new FutureTask<Integer>(oneCallable);
FutureTask<Integer>是一个包装器,它通过接受Callable<Integer>来创建,它同时实现了Future和Runnable接口,他的run方法中实际上会调用oneCallable.call()。


步骤4:由FutureTask<Integer>创建一个Thread对象:


       Thread oneThread = new Thread(oneTask);
  
步骤5:启动线程:


       oneThread.start();
  
  
  
2、通过线程池来创建线程:


步骤1:创建线程池:


      ExecutorService pool = Executors.newCachedThreadPool();


步骤2:通过Runnable对象或Callable对象将任务提交给ExecutorService对象:


      Future<Integer> submit(Callable<Integer> task);



网上的例子

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. import java.util.concurrent.*;  
  2.   
  3. public class Test {  
  4.   
  5.       
  6.     public static void main(String[] args) throws InterruptedException,  
  7.             ExecutionException {  
  8.         final ExecutorService exec = Executors.newFixedThreadPool(5);  
  9.         Callable<String> call = new Callable<String>() {  
  10.             public String call() throws Exception {  
  11.                 Thread.sleep(1000 * 10);//休眠指定的时间,此处表示该操作比较耗时  
  12.                 return "Other less important but longtime things.";  
  13.             }  
  14.         };  
  15.         Future<String> task = exec.submit(call);  
  16.         //重要的事情  
  17.         System.out.println("Let's do important things. start");  
  18.         Thread.sleep(1000 * 3);  
  19.         System.out.println("Let's do important things. end");  
  20.   
  21.         //不重要的事情  
  22.         while(! task.isDone()){  
  23.             System.out.println("still waiting....");  
  24.             Thread.sleep(1000 * 1);  
  25.         }  
  26.         System.out.println("get sth....");  
  27.         String obj = task.get();  
  28.         System.out.println(obj);  
  29.         //关闭线程池  
  30.         exec.shutdown();  
  31.     }  
  32. }  

输出结果:

Let's do important things. start
Let's do important things. end
still waiting....
still waiting....
still waiting....
still waiting....
still waiting....
still waiting....
still waiting....
get sth....
Other less important but longtime things.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值