目录
一、Callable接口的含义
二、Callable接口的使用
步骤一:明确执行任务的内容及其返回值
步骤二:把任务交给线程来执行
步骤三:获取任务的返回值
一、Callable接口的含义
Callable接口和runnable接口类似,本质上描述的也是任务。
但是,Callable接口相比于Runnable接口,新增了两个功能:
①让执行的任务拥有了返回值,返回值的类型为Callable接口当中的泛型
比如执行一个++操作,让某个变量的值自增。这个时候,如果使用runnable接口来执行这个任务,那么一定要在run()方法外部新建一个变量收集自增之后的值。
但是,如果使用了Callable接口,让自增过后的值直接返回,这样就更加地方便。
Callable<Integer> callable= new Callable<Integer>() {//类似于runnable的run方法//返回值是泛型参数@Overridepublic Integer call() throws Exception {int i;for( i=0;i<1000;i++){i++;}return i;}};
②让执行过程中出现的异常可以及时被声明
回顾一下throws关键字的含义:
这个关键字的含义就是声明方法内部可能发生的异常。
当运行时候,如果发生了异常,没有进行及时的处理,那么这个异常就会抛出给它的调用者处理。
那么,在这个程序当中。如果发生了异常,会交给谁处理呢?
①方法内部如果及时处理了异常,那么按照方法内部处理异常的逻辑来进行处理;
②如果方法内部没有及时处理异常,那么会抛给调用get()方法获取返回值的线程来处理
③如果没有get()方法获取,那么这个异常就会交给jvm来处理,那么也就意味着这个线程会被提前终止。
二、Callable接口的使用
步骤一:明确执行任务的内容及其返回值
代码上面的实现,主要是依托指定Callable接口指定的泛型以及重写接口当中的run()方法。
步骤二:把任务交给线程来执行
创建一个FutureTask对象,泛型为构造方法当中callable接口任务的泛型。
创建一个线程对象t,把FutureTask的实例作为参数传递给线程对象t。
启动线程
步骤三:获取任务的返回值
是通过task.get()方法获取任务的返回值的。
需要注意的是,如果执行任务的线程没有执行完毕,那么,获取返回值的线程,也就是调用task.get()方法的线程,需要阻塞等待。
此时main线程为调用get()方法的线程,那么也就意味着main线程需要阻塞等待,直到任务执行完毕,获取到返回值。
整体代码实现:
public class ThreadDemo29 {public static void main(String[] args) {Callable<Integer> callable= new Callable<Integer>() {//类似于runnable的run方法//返回值是泛型参数@Overridepublic Integer call() throws Exception {int i;for( i=0;i<100;i++){i++;}return i;}};//不可以直接传入callable接口//Thread t=new Thread(callable);//未来的任务FutureTask<Integer> task=new FutureTask<>(callable);Thread t=new Thread(task);//启动线程t.start();try {Integer result=task.get();System.out.println(result);} catch (InterruptedException|ExecutionException|ArithmeticException e) {e.printStackTrace();}}
}