在一般的使用线程的过程中 我们都知道是不可以返回线程的执行结果的 如果想要获取线程的执行结果 就需要线程间通信或者设置某些标志位来判断是否执行完来获取
但是jdk1.5 提供了ExecutorService Future FutureTask Callbale 这几个类 可以让我们实现简单的返回执行结果的线程 下面我们来看看各个类的作用和组成
首先是 Future类:
public interface Future<V> { boolean cancel(boolean mayInterruptIfRunning); boolean isCancelled(); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }这个类 主要是提供对具体Callable 和Runnable 的执行过程的检查 是否取消 是否结束 获取执行结果 get方法 是用来获取线程执行结果的 这个方法 会 阻塞 直到任务结束 还有一个重载的get方法 这个方法会规定一个时间 如果这个时间内 任务没有执行完成那么 返回null
Future类只是一个接口 他有一个唯一实现类FutrueTask:
我们先来看一下FutureTask的实现:
我们先来看一下FutureTask的实现:
1
|
public
class
FutureTask<V>
implements
RunnableFuture<V>
|
FutureTask类实现了RunnableFuture接口,我们看一下RunnableFuture接口的实现:
1
2
3
|
public
interface
RunnableFuture<V>
extends
Runnable, Future<V> {
void
run();
}
|
可以看出RunnableFuture继承了Runnable接口和Future接口,而FutureTask实现了RunnableFuture接口。所以它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值。
FutureTask提供了2个构造器:
1
2
3
4
|
public
FutureTask(Callable<V> callable) {
}
public
FutureTask(Runnable runnable, V result) {
}
|
继续看 ExecutorService类:
这个类有submit方法 可以提交任务在未来的某个时间执行(不是立即执行的) 下面是他的方法:
public interface ExecutorService extends Executor { void shutdown(); List<Runnable> shutdownNow(); boolean isShutdown(); boolean isTerminated(); boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException; <T> Future<T> submit(Callable<T> task); <T> Future<T> submit(Runnable task, T result); Future<?> submit(Runnable task); <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException; <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException; <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException;
<T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }而 Callable 接口和Runnable接口类似 只不过它带有一个泛型V
以下Callable和Runnable内容取自
http://www.cnblogs.com/dolphin0520/p/3949310.html
先说一下java.lang.Runnable吧,它是一个接口,在它里面只声明了一个run()方法:
1
2
3
|
public
interface
Runnable {
public
abstract
void
run();
}
|
由于run()方法返回值为void类型,所以在执行完任务之后无法返回任何结果。
Callable位于java.util.concurrent包下,它也是一个接口,在它里面也只声明了一个方法,只不过这个方法叫做call():
1
2
3
4
5
6
7
8
9
|
public
interface
Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call()
throws
Exception;
}
|
可以看到,这是一个泛型接口,call()函数返回的类型就是传递进来的V类型。
那么怎么使用Callable呢?一般情况下是配合ExecutorService来使用的,在ExecutorService接口中声明了若干个submit方法的重载版本:
1
2
3
|
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);
|
第一个submit方法里面的参数类型就是Callable。
暂时只需要知道Callable一般是和ExecutorService配合来使用的,具体的使用方法讲在后面讲述。
一般情况下我们使用第一个submit方法和第三个submit方法,第二个submit方法很少使用。
下面写一个例子:
public class MyClass { public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService executorService = Executors.newCachedThreadPool(); //运用线程池技术 当然也可以直接使用线程 MyTask task = new MyTask(); //创建一个任务对象 //第一种方式 直接使用 Future
<span style="white-space:pre"> </span>Future<Integer> future = executorService.submit(task); //提交任务
//第二种方式 使用 FutureTask
// FutureTask<Integer> future= new FutureTask<Integer>(task); // executorService.submit(futureTask);
//第三种方式 直接使用Thread 不使用线程池
// <span style="font-family: Verdana, Arial, Helvetica, sans-serif;">FutureTask<Integer> future= new FutureTask<Integer>(task);</span>
//Thread thread = new Thread(futureTask); //thread.start(); int a = future.get(); System.out.println("----"+a); } static class MyTask implements Callable<Integer>{ @Override public Integer call() throws Exception { //此方法内含耗时任务 Thread.sleep(3000); int count = 0; for(int i = 0;i<100;i++){ count+=i; } return count; } } }