JUC并发编程快速入门篇(五)—— Callable&Future 接口
Callable接口
Callable 接口实现多线程的特点如下(重点)
-
为了实现 Runnable,需要实现不返回任何内容的 run()方法,而对于Callable,需要实现在完成时返回结果的 call()方法。简而言之Runnable接口没有返回值,Callable接口有返回值
-
call()方法可以引发异常,而 run()则不能。
-
为实现 Callable 而必须重写 call 方法
-
不能直接替换 runnable,因为 Thread 类的构造方法根本没有 Callable
//创建新类 MyThread 实现 runnable 接口
class MyThread implements Runnable{
@Override
public void run() {
}
}
//新类 MyThread2 实现 callable 接口
class MyThread2 implements Callable<Integer>{
@Override
public Integer call() throws Exception {
return 200;
}
}
Callable&FutureTask实现多线程
常用方法
public boolean cancel(boolean mayInterrupt): 用于停止任务。如果尚未启动,它将停止任务。如果已启动,则仅在 mayInterrupt 为 true时才会中断任务。
public Object get()抛出 InterruptedException,ExecutionException: 用于获取任务的结果。如果任务完成,它将立即返回结果,否则将等待任务完成,然后返回结果。
public boolean isDone(): 如果任务完成,则返回 true,否则返回 fals
案例
//实现Callable接口
class MyThread2 implements Callable{
@Override
public Integer call() throws Exception {
return 2;
}
}
public class Demo1 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//Runnable方式创建线程
new Thread(new MyThread1(),"线程一").start();
//Callable方式创建线程
// new Thread(new MyThread2(),"线程二").start(); //错误写法
//FutureTask
//FutureTask<Integer> futureTask1 = new FutureTask<>(new MyThread2());
//lam表达式简化
FutureTask<Integer> futureTask2 = new FutureTask<>(()->{
System.out.println(Thread.currentThread().getName()+"come in callable");
return 1024;
});
//FutureTask<Integer> futureTask3 = new FutureTask<>(() -> 1024);
//创建线程
new Thread(futureTask2,"线程二").start();
while (!futureTask2.isDone()){ //1.任务未完成输出 wait
System.out.println("wait");
}
//调用FutureTask的get方法
System.out.println(futureTask2.get());//2.任务完成 输出1024
System.out.println(Thread.currentThread().getName()+"come over"); //主线程over
}
}
FutureTask
Java 库具有具体的 FutureTask 类型,该类型实现 Runnable 和 Future,并方便地将两种功能组合在一起。 可以通过为其构造函数提供 Callable 来创建FutureTask。然后,将 FutureTask 对象提供给 Thread 的构造函数以创建Thread 对象。因此,间接地使用 Callable 创建线程。
核心原理:(重点)
在主线程中需要执行比较耗时的操作时,但又不想阻塞主线程时,可以把这些作业单开一个线程交给 Future 对象在后台完成
- 当主线程将来需要时,就可以通过 Future 对象获得后台作业的计算结果或者执行状态
- 一般 FutureTask 多用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果。
- 仅在计算完成时才能检索结果;如果计算尚未完成,则阻塞 get 方法
- 一旦计算完成,就不能再重新开始或取消计算
- get 方法而获取结果只有在计算完成时获取,否则会一直阻塞直到任务转入完成状态,然后会返回结果或者抛出异常
- get 只计算一次,因此 get 方法放到最后