Future和Callable的使用

在默认情况下,线程Thread对象不具有返回值的功能,如果在需要取得返回值的情况下是极为不方便的,但在JDK1.5的并发包中可以使用Future和Callable来使线程具有返回值的功能。

接口Callable和Runnable的区别
1、Callable接口的call()方法可以有返回值,而Runnable接口的run()方法没有返回值。
2、Callable()接口的call()方法可以声明抛出异常,而Runnable接口的run()方法不可以声明异常。

执行完Callable接口中的任务后,返回值是通过Future接口进行获取;
Callable示例

1
2
3
4
5
6
7
8
9
10
11
12
public class App {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ThreadPoolExecutor pool = new ThreadPoolExecutor(2, 3, 5, TimeUnit.SECONDS, new LinkedBlockingDeque<>());
Future<String> future = pool.submit(() -> {
Thread.sleep(5000);
return "Finished";
});
System.out.println("main A:" + System.currentTimeMillis());
System.out.println(future.get());
System.out.println("main B:" + System.currentTimeMillis());
}
}

运行结果

1
2
3
main A:1525698162505
Finished
main B:1525698167510

从结果看出,get()方法具有阻塞的特性

Runnable示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class App {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ThreadPoolExecutor pool = new ThreadPoolExecutor(2, 3, 5, TimeUnit.SECONDS, new LinkedBlockingDeque<>());
Future<?> future = pool.submit(() -> {
try {
System.out.println("运行开始:" + System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("运行结束:" + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println("main A:" + System.currentTimeMillis());
System.out.println(future.get() + " | " + future.isDone());
System.out.println("main B:" + System.currentTimeMillis());
}
}

运行结果

1
2
3
4
5
main A:1525698748640
运行开始:1525698748640
运行结束:1525698753643
null | true
main B:1525698753643

从结果看出Runnable是没有返回值的,所以get()方法打印null,且也具有阻塞的特性,而isDone()方法无阻塞特性
Callable接口相对于Runnable接口的优点在于Callable接口可以通过Future获取返回值,但需要注意的是,Future接口调用get()方法时,是呈阻塞性的,也就是如果任务尚未完成,则调用get()方法时一直阻塞到此任务完成为止

异常处理
Callable任务如果执行过程中抛出来异常,会在对应的Future的get()方法中抛出

方法execute()与submit()的区别
1、execute()没有返回值,submit()可以有返回值
2、execute()默认情况下异常直接抛出,不能捕获,但可以通过自定义ThreadFactory的方式进行捕获(Thread.setUncaughtExceptionHandler(UncaughtExceptionHandler eh)),
submit()方法在默认情况下,可以在对应的Future.get方法处捕获异常

Future的缺点:get()方法呈阻塞性,影响效率

方法介绍

1
2
3
4
5
6
7
8
9
ExecutorService接口的
submit(Callable callable)
submit(Runnable runnable)
submit(Runnable runnable, T result)第二个参数可作为执行结果返回,而不需要使用get()方法来进行获取

Future
cancel(boolean mayInterruptIfRunning)参数的作用是:如果线程正在运行则是否中断中断正在运行的线程,在代码中需要使用if(Thread.currentThread().isInterrupted())进行配合。返回值代表发送取消任务的命令是否成功完成
get()
get(long timeout, TimeUnit unit)指定的最大时间内等待获取返回值