上次介绍了Callable实现多线程的方法。现在介绍和Callable搭配的类。上一篇只是简单的用Callable做了一个demo。
一、Future
1.关于callable和runable的区别(上次已经介绍)
-
Callable可以在任务结束的时候提供一个返回值Future对象,Runnable无法提供这个功能
-
Callable的call方法分可以抛出异常,而Runnable的run方法不能抛出异常。
-
Callable规定的方法是call(),而Runnable规定的方法是run().
2.Future介绍
Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果。必要时可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果。
Future类位于java.util.concurrent包下,它是一个接口:
public
interface
Future
boolean
cancel(
boolean
mayInterruptIfRunning);
boolean
isCancelled();
boolean
isDone();
V get()
throws
InterruptedException, ExecutionException;
V get(
long
timeout, TimeUnit unit)
throws
InterruptedException, ExecutionException, TimeoutException;
}
|
在Future接口中声明了5个方法,下面依次解释每个方法的作用:
- cancel方法用来取消任务,如果取消任务成功则返回true,如果取消任务失败则返回false。参数mayInterruptIfRunning表示是否允许取消正在执行却没有执行完毕的任务,如果设置true,则表示可以取消正在执行过程中的任务。如果任务已经完成,则无论mayInterruptIfRunning为true还是false,此方法肯定返回false,即如果取消已经完成的任务会返回false;如果任务正在执行,若mayInterruptIfRunning设置为true,则返回true,若mayInterruptIfRunning设置为false,则返回false;如果任务还没有执行,则无论mayInterruptIfRunning为true还是false,肯定返回true。
- isCancelled方法表示任务是否被取消成功,如果在任务正常完成前被取消成功,则返回 true。
- isDone方法表示任务是否已经完成,若任务完成,则返回true;
- get()方法用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回;
- get(long timeout, TimeUnit unit)用来获取执行结果,如果在指定时间内,还没获取到结果,就直接返回null。
也就是说Future提供了三种功能:
1)判断任务是否完成;
2)能够中断任务;
3)能够获取任务执行结果。
因为Future只是一个接口,所以是无法直接用来创建对象使用的,因此就有了FutureTask。
3.测试
public
class
TestCallable {
public
static
void
main(String[] args) {
ExecutorService executor = Executors.newCachedThreadPool();
Task task =
new
Task();
Future
executor.shutdown();
try
{
Thread.sleep(
1000
);
}
catch
(InterruptedException e1) {
e1.printStackTrace();
}
System.out.println(
"主线程在执行任务"
);
try
{
System.out.println(
"task运行结果"
+result.get());
}
catch
(InterruptedException | ExecutionException e) {
e.printStackTrace();
}
System.out.println(
"所有任务执行完毕"
);
}
}
class
Task
implements
Callable
@Override
public
Integer call()
throws
Exception {
System.out.println(
"子线程在进行计算"
);
Thread.sleep(
3000
);
int
sum =
0
;
for
(
int
i=
0
;i<
100
;i++){
sum += i;
}
return
sum;
}
}
|
结果:
子线程在进行计算
主线程在执行任务
task运行结果4950
所有任务执行完毕
二、FutureTask
1.FutureTask的实现
public
class
FutureTask
implements
RunnableFuture
FutureTask类实现了RunnableFuture接口,我们看一下RunnableFuture接口的实现:
public
interface
RunnableFuture
extends
Runnable, Future
void
run();
}
可以看出RunnableFuture继承了Runnable接口和Future接口,而FutureTask实现了RunnableFuture接口。
也就是说:
FutureTask实现了Runnable,因此它既可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行。
FutureTask实现了Futrue可以直接通过get()函数获取执行结果,该函数会阻塞,直到结果返回。
FutureTask提供了2个构造器:
public
FutureTask(Callable
}
public
FutureTask(Runnable runnable, V result) {
}
FutureTask是Future接口的一个实现类(唯一的实现类)。
2.测试
public
class
FutureTaskTest {
public
static
void
main(String[] args) {
ExecutorService executor = Executors.newCachedThreadPool();
newTask task =
new
newTask();
FutureTask
new
FutureTask
executor.submit(futureTask);
executor.shutdown();
try
{
Thread.sleep(
1000
);
}
catch
(InterruptedException e1) {
e1.printStackTrace();
}
System.out.println(
"主线程在执行任务"
);
try
{
System.out.println(
"task运行结果"
+ futureTask.get());
}
catch
(InterruptedException | ExecutionException e) {
e.printStackTrace();
}
System.out.println(
"所有任务执行完毕"
);
}
}
class
newTask
implements
Callable
@Override
public
Integer call()
throws
Exception {
System.out.println(
"子线程在进行计算"
);
Thread.sleep(
3000
);
int
sum =
0
;
for
(
int
i =
0
; i <
100
; i++){
sum += i;
}
return
sum;
}
}
|
结果:
子线程在进行计算
主线程在执行任务
task运行结果4950
所有任务执行完毕