在我们传统的观念中,创建线程无非就两种方式:1、直接new 一个Thread;2、实现Runnable,其实这两种方式的实质是一样的,有一个共同的特点:无返回值,并且无法抛出返回结果的异常,顺便我们讲一下其他的线程创建方式。那我们想拿到线程的返回值,怎么做了?我们可以使用java并发包中的Callable和Future来实现。下面就来分享一下实现方式。
1、Callable接口
Callable接口的原型如下:
- public interface Callable<V> {
- V call() throws Exception;
- }
这个接口设计之初有两个目的:1、解决任务有返回的问题;2、解决任务抛异常的问题,该接口只定义了一个方法,就是call,其实Callable接口和Runnable接口很类似,都是设计用来执行多线程的,唯一的不同就是Runnable没有返回值和抛异常。
1、Future接口
Future接口的原型如下:
- public interface Future<V> {
- // 试图取消一个执行的任务,如果该任务已经执行完毕,或者已经取消,或者是一些无法取消的原因,则返回false,正常取消则返回true,如果成功取消,则这个任务不会启动,如果当前任务正在执行,且mayInterruptIfRunning设置为true,则正在执行的任务会被中断,此时,如果调用isCancelled和isDone方法来判断当前任务是否执行完,或者是是否取消,则会返回true
- boolean cancel(boolean mayInterruptIfRunning);
- // 判断任务是否被取消
- boolean isCancelled();
- // 判断任务是否已经完成
- boolean isDone();
- // 获取返回值,等待任务执行完成后,对返回结果进行一个检索,否则就会阻塞,知道任务转成执行完成状态
- V get() throws InterruptedException, ExecutionException;
- // 获取返回值,会在等待最大的给定时间后,对返回结果进行一个检索,否则抛对应的异常,而不会一直阻塞
- V get(long timeout, TimeUnit unit)
- throws InterruptedException, ExecutionException, TimeoutException;
- }
1、使用示例
看完了这两个接口的定义和含义,下面我们做一个简单的示例,方便大家理解。
3.1 单个返回结果的示例
代码如下:
- public void demo(){
- /*
- * 创建线程,这种线程的创建方式也是jdk1.5提供的,是java推荐的方式,如果对这种方式感兴趣
- * 可以看我之前写的一篇博客<a href="http://blog.csdn.net/liuchuanhong1/article/details/52042182">http://blog.csdn.net/liuchuanhong1/article/details/52042182</a>
- * 以下是创建一个单一线程的线程池
- */
- ExecutorService service = Executors.newSingleThreadExecutor();
- // 注意,此处需用submit来提交任务,这样才会有返回值,如果使用Execute来提交任务,则无返回值
- Future<String> result = service.submit(new Callable<String>() {
- public String call() throws Exception {
- // 可能需要处理的业务逻辑
- Thread.sleep(2000);
- // 返回业务逻辑处理的结果
- return "chhliu";
- }
- });
- try {
- Thread.sleep(2000);
- String resultStr = result.get();
- System.out.println("the result is: "+resultStr);
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
- }
- }
测试类及测试结果如下:
the result is: chhliu
从测试结果可以看出,我们是拿到了任务的返回结果的。
3.2 多个返回结果的示例
代码如下:
- /**
- * 描述:多返回值的示例
- * void
- */
- public List<Future<String>> demo1(){
- // 创建多个线程
- ExecutorService service = Executors.newCachedThreadPool();
- List<Future<String>> list = new ArrayList<Future<String>>();
- for(int i=0; i<10; i++){
- Future<String> result = service.submit(new Callable<String>() {
- @Override
- public String call() throws Exception {
- return Thread.currentThread().getName();
- }
- });
- list.add(result);
- }
- return list;
- }
- /**
- * 描述:多返回值的示例,另一种实现方式
- * @author chhliu
- * void
- */
- public CompletionService<String> demo2(){
- // 创建多个线程
- ExecutorService service = Executors.newCachedThreadPool();
- CompletionService<String> completion = new ExecutorCompletionService<String>(service);
- for(int i=0; i<10; i++){
- completion.submit(new Callable<String>() {
- @Override
- public String call() throws Exception {
- return Thread.currentThread().getName();
- }
- });
- }
- return completion;
- }
上面是两种方式实现的多返回值的使用示例,测试结果如下:
- the current thread name is: pool-1-thread-1
- the current thread name is: pool-1-thread-2
- the current thread name is: pool-1-thread-2
- the current thread name is: pool-1-thread-2
- the current thread name is: pool-1-thread-2
- the current thread name is: pool-1-thread-4
- the current thread name is: pool-1-thread-6
- the current thread name is: pool-1-thread-3
- the current thread name is: pool-1-thread-1
- the current thread name is: pool-1-thread-5
从上面的测试结果中,我们不难看出,任务的返回结果我们都拿到了,拿到这个返回结果之后,我们就可以对这些结果做进一步的处理。
其实,在jdk1.5中,还为我们提供了另外一个类,来实现上面的功能,就是FutureTask,这个类的原型如下:
- public class FutureTask<V> implements RunnableFuture<V>
- public interface RunnableFuture<V> extends Runnable, Future<V>
从上面的类实现和继承关系上来看,FutureTask类实现了Runnable和Future这两个接口,所以说,这个类兼顾了两者的优点,我们在使用的时候,既可以通过Executors,也可以通过Thread来使用,如果在主线程中需要执行比较耗时的操作时,但又不想阻塞主线程时,可以把这些作业交给Future对象在后台完成,当主线程将来需要时,就可以通过Future对象获得后台作业的计算结果或者执行状态。下面,我们就用FutureTask类,实现上面示例1,代码如下:
- /**
- * 描述:使用FutureTask来实现上面的示例
- */
- public String demo3() throws InterruptedException, ExecutionException{
- Callable<String> call = new Callable<String>() {
- @Override
- public String call() throws Exception {
- return "chhliu";
- }
- };
- FutureTask<String> task = new FutureTask<String>(call);
- ExecutorService service = Executors.newSingleThreadExecutor();
- service.submit(task);
- return task.get();
- }
测试结果如下:
the result is: chhliu
也就是说,我们同样拿到了任务的返回结果。
关于Callable和Future的内容,我们就讲到这里