一:什么是Future ?
Future 接口是 Java 多线程编程中的一个核心概念,用来表示异步计算任务的结果。它定义了一组方法,可以用来查询任务是否已经完成、获取任务的返回值或者等待任务完成后获取其返回值
当我们需要从网络上下载一个大文件时,因为网络速度的限制,下载操作需要花费一些时间来完成,如果在主线程中同步执行下载操作,会导致界面卡顿,用户体验不好。这时就可以使用 Future 接口来异步执行下载操作,将下载任务交给另一个线程去执行,主线程可以继续执行其他操作,等待下载任务完成后再获取下载结果。
import java.util.concurrent.*;
public class FutureExample {
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService executorService = Executors.newSingleThreadExecutor();
// 执行一个需要时间较长的下载任务,并返回一个 Future 对象
Future<String> future = executorService.submit(() -> {
System.out.println("Downloading...");
Thread.sleep(5000); // 模拟下载操作需要 5s
return "Downloaded file";
});
// 主线程可以继续执行其他操作,异步任务在另一个线程中执行
System.out.println("Do something else...");
// 等待异步任务完成,并获取任务的返回结果
System.out.println("Wait result...");
String result = future.get();
System.out.println("Result: " + result);
executorService.shutdown(); // 关闭线程池
}
}
二:什么是FutureTask?
FutureTask是Future 的常用子类,
此时当我们去通过new thread 创建一个线程,thread 类如下
public class Thread implements Runnable
只能通过传Runnable的方式创建
此时,juc下提供了RunnableFuture接口,同时继承了Runnable和Future如下
public interface RunnableFuture<V> extends Runnable, Future<V>
此时可以通过new Thread(FutureTask)
的方式创建线程
三:创建线程
每次都通过手动创建比较繁琐,时伴随垃圾回收,开销大,可以通过线程池的方式创建线程
executorService=Executors.newFixedThreadPool(3);
这段代码就是线程池中已经创建三个线程
四: Future弊端
以上案例中有一个get方法:
在获取Future中的结果时,可以通过调用Future对象的get()方法来阻塞等待异步任务的结果返回。如果异步任务还没有完成,则get()方法会一直阻塞直到任务完成并返回结果。如果任务执行过程中出现异常,则get()方法会抛出异常。此方法有以下弊端
01 阻塞主线程: Future.get()方法是阻塞的,意味着在调用该方法时,主线程将等待异步任务完成。这可能会导致主线程被阻塞,并影响应用程序的性能和响应性
02 无法取消任务: Future.get()方法是无法取消的,这意味着如果您的异步任务正在执行中,您只能等待它完成
五:CompletableFuture对Future的改进
CompletableFuture 实现非阻塞的方式是使用回调函数。当异步任务完成时,CompletableFuture 会自动调用注册的回调函数,而不是阻塞当前线程等待结果。这样可以避免阻塞线程,提高程序的并发性能。
下面是一个使用 CompletableFuture 实现异步任务的例子
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// 异步任务
return "Hello, world!";
});
// 注册回调函数
future.thenAccept(result -> {
System.out.println("异步任务完成,结果为:" + result);
});
// 主线程继续执行其他任务
System.out.println("主线程继续执行其他任务...");
六:如何创建CompletableFuture
1 runAsync 无返回值(传runnable接口)
不指定线程池,使用默认的,,指定线程池就用我们自己的
2 supplyAsync 有返回值(传Supplier)