0%

Callable接口

Callable接口

Runnable的缺陷

在创建线程的时候不管是继承Thread类(Thread本身也是实现的Runnable接口)还是实现Runnable接口,所实现的run()方法都没有返回值,使得需要将返回值写到map中,等到线程结束再去从map中取数据,特别的不方便

而且Runnable还有另一个问题是不能抛出任何异常,必须在run()方法中自己处理异常。

由于Runnable存在的两个问题,所以Callable接口和Future接口应运而生,这里来介绍一下Callable接口和Future接口

Callable的改善

Callable与Runnable不同,提供的方法为call()方法,大家看到,该方法是有返回值的,且可以抛出异常

获取Callable的返回值需要FutureTask的支持

1
2
3
4
5
6
7
8
9
public interface Callable<V> {

V call() throws Exception;
}

public interface Runnable {

public abstract void run();
}

Runnable和Callable接口的区别

  • Runnable中提供的是run()方法,Callable中提供的是call()方法
  • Runnable中的run()方法返回值为void,Callable中的call()方法有返回值
  • Runnable的run()方法不能抛出异常,Callable中的call方法可以抛出异常
  • Callable可以和Future、FutureTask配合获取异步执行的结果

自旋锁执行时间短、线程数少的时候使用(由于占用CPU) —–> Atomic和lock都是使用的自旋锁

FutureTask

Future接口

使用ExecutorService来执行Callable对象

1
<T> Future<T> submit(Callable<T> task);

看到该方法返回的是一个Future对象,Future对象是什么呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public interface Future<V> {

// 在任务正常结束之前可以尝试取消任务,如果任务已完成或已取消,则次尝试失败。如果调用成功,且此任务还没有启动,则该任务将不会执行;如果任务已经启动,则mayInterruptIfRunning参数确定是否应该以试图停止任务的方式来中断此任务的线程
boolean cancel(boolean mayInterruptIfRunning);

// 如果任务正常结束之前被取消,isCancelled会返回true
boolean isCancelled();

// 检测任务是否结束,任务完成返回true,由于正常终止、异常或取消而完成,也会返回true
boolean isDone();

// get方法会将结果返回给调用方
V get() throws InterruptedException, ExecutionException;

// get方法会将结果返回给调用方,可以限制限制超时时间
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}

但是线程中没有可以使用Callable接口和Future接口的地方,Thread唯一可用的参数是Runnable对象,那么如何才能用到这个好用的技术呢?

答案是FutureTask

FutureTask类

FutureTask类同时实现了Runnable接口和Future接口,同时拥有异步能力以及取消任务的能力,可以创建出可取消的任务

1
2
3
4
5
6
public class FutureTask<V> implements RunnableFuture<V> 

public interface RunnableFuture<V> extends Runnable, Future<V> {

void run();
}

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class TestCallable {

public static void main(String[] args) {
CallDemo call = new CallDemo();
FutureTask<Integer> futureTask = new FutureTask<>(call);
new Thread(futureTask).start();

try {
// get方法是一个阻塞方法 在没有执行结束之前一直阻塞,直到执行完毕
int sum = futureTask.get();
System.out.println("---------");
System.out.println(sum);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}

}
}

/**
* Callable相较于Runnable有返回值和异常
*/
class CallDemo implements Callable<Integer>{

@Override
public Integer call() throws Exception {
int sum = 0;
for(int i = 0;i<1000;i++){
sum +=i;
}
return sum;
}
}