我们都知道线程真正执行的方法体内容是Thread的run方法,run方法执行完毕后,也就意味线程执行结束。
然后Thread的run方法它通过一个策略模式交给了Runable接口的run方法。但是这个方法时没有返回值的(如果我们需要启动线程执行任务想在线程执行完毕后得到任务执行结果。这就需要用到java1.5开始提供的Callable和Future)。
Callable位于java.util.concurrent包下的,它也是一个接口,在它里面也只是声明了一个call()方法。
Callabel和Runable的区别:
1 一个定义的是call()方法,一个定义的是run方法。
2 call方法可以返回执行任务后的结果,run方法无法获得返回值。
3 call方法中定义了throws Execption抛出异常,抛出的异常可以在主线程Future.get()时被主线程捕获;Runable中的run方法没有定义抛出异常,运行任务时发生异常时也会上抛,但异常无法被主线程获取。
4 运行Callable任务可以拿到一个Future对象代表异步运算的结果。
Future接口就是对于具体的Runnable或者Callable任务的执行结果进行取消,查询是否完成,获取结果,必要时可以通过get方法获取执行结果,但该方法会阻塞直到任务返回结果。(会一直等到到任务执行完才返回)
get(): 用来获取执行结果。这个方法会产生阻塞,会一直等到任务执行完毕后才返回。
V get(long,TimeUnit):获取异步执行结果,如果没有结果可用,此方法会阻塞,但是会有时间限制,如果阻塞时间超过设定的timeout时间,该方法会抛出异常。
boolean isDone():如果任务执行结束,无论是正常结束或是中途取消还是发生异常,都返回true。
boolean isCancelled():如果任务完成前被取消,返回true。
接下来我们在看一个接口RunnableFuture接口,它继承了Runnable接口和Future接口,而FutureTask实现了RunableFuture接口,所以它既可以作为Runable被线程执行,又可以作为Future得到Callable的返回值。
画一个类图简单明了,亿图软件画的
我们通过一个线程运行Callable,但是Thread目前不支持构造方法传递Callable实例,所以我们需要通过FutureTask把一个Callable包装成Runable,然后再通过这个FutureTask拿到Callable运行后的返回值。
现在我们来模拟下需要获取执行完任务返回值的情景。
我们可以明显看到在主线程中获取了子线程执行完毕的结果。
如果我们在子线程中抛出了异常了,这种情况我们也是可以捕获的。
网友评论