Runnable、Callable、Future、FutureTask
一:并发编程的核心
并发编程的核心问题:分工、同步和互斥。
要编写高质量的并发程序,只需要处理好分工、同步和互斥的问题即可,同步和互斥对应的就是管程模型。
二:Runnable、Callable、Future、FutureTask
1:Runnable、Callable、Future、FutureTask的UML类图
Callable与Runnable、Future、FutureTask无继承关系。
FutureTask带了Future和Runnable的功能。
2:Runnable和Callable
// JDK1.0 不接受参数、无返回值,单线程、线程池均可使用。
public interface Runnable {
public abstract void run();
}
// JDK 1.5 不接受参数、有返回值,仅供线程池使用。
public interface Callable<V> {
V call() throws Exception;
}
3:Future API
// 取消任务
boolean cancel( boolean mayInterruptIfRunning);
// 判断任务是否已取消
boolean isCancelled();
// 判断任务是否已结束
boolean isDone();
// 获得任务执行结果 ---> 阻塞方法
get();
// 获得任务执行结果,支持超时 ---> 阻塞方法
get(long timeout, TimeUnit unit);
4:为什么要引入FutureTask?为什么要让FutureTask实现Runnable?
在单线程和多线程执行Task的时候,都有获取执行结果的需求,但是当使用Runnable的时候,Runnable的API是拿不到返回值的,因此可以用FutureTask类包装Runnable来拿返回值。
所以:Runnable、Callable、Future、FutureTask存在的目的是为了使用更加灵活。
获取执行结果:
- 单线程:FutureTask包装Callable和Runnable,通过FutureTask获取返回值。
- 多线程:单独使用Callable能获取返回值,FutureTask包装Callable和Runnable能获取返回值。
5:使用示例
/**
* <p>
* Runnable、Callable、Future、FutureTask
* </p>
*
* @author: Sunny
* @date: 2021/2/1
* @version: v1.0.0
*/
public class TaskTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 1:单线程 + Callable + FutureTask拿到返回结果
FutureTask<Integer> task = new FutureTask<Integer>(() -> {
return 1 + 1;
});
Thread t1 = new Thread(task);
t1.start();
System.out.println(task.get());
// 2:单线程 + Runnable + T result + FutureTask拿到返回结果
Account account = new Account();
FutureTask<Account> task1 = new FutureTask<Account>(() -> {
account.setName("zhangsan");
account.setAge(3);
}, account);
Thread t2 = new Thread(task1);
t2.start();
System.out.println(task1.get().getName() + " : " + task1.get().getAge());
System.out.println(account.getName() + " : " + account.getAge());
// 3:线程池 + Callable + Future拿到返回结果
ExecutorService service = Executors.newSingleThreadExecutor();
Future<Integer> future = service.submit(() -> 1 + 1);
System.out.println(future.get());
// 4:线程池 + Runnable + Future拿不到返回结果
Future<?> future1 = service.submit(() -> System.out.println(1));
// Runnable 不接受返回值,因此其值为null
System.out.println(future1.get());
// 5:线程池 + Runnable + T result + Future拿到返回结果
Account account1 = new Account();
Future<Account> future2 = service.submit(() -> {
account1.setName("xiaoming");
account1.setAge(4);
}, account1);
System.out.println(future2.get().getName() + " : " + future2.get().getAge());
System.out.println(account1.getName() + " : " + account1.getAge());
service.shutdown();
}
@Data
public static class Account {
private String name;
private Integer age;
}
}