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

来源:互联网 发布:js删除span标签 编辑:程序博客网 时间:2024/05/16 18:56

在我们传统的观念中,创建线程无非就两种方式: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方法来判断当前任务是否执行完,或者是是否取消,则会返回trueboolean 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推荐的方式,如果对这种方式感兴趣 *  可以看我之前写的一篇博客http://blog.csdn.net/liuchuanhong1/article/details/52042182 *  以下是创建一个单一线程的线程池 */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>() {@Overridepublic 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>() {@Overridepublic String call() throws Exception {return Thread.currentThread().getName();}});}return completion;}

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

the current thread name is: pool-1-thread-1the current thread name is: pool-1-thread-2the current thread name is: pool-1-thread-2the current thread name is: pool-1-thread-2the current thread name is: pool-1-thread-2the current thread name is: pool-1-thread-4the current thread name is: pool-1-thread-6the current thread name is: pool-1-thread-3the current thread name is: pool-1-thread-1the 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>() {@Overridepublic 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的内容,我们就讲到这里

0 0