Java中,实现异步编程的方式多种多样,每种方式都有其特定的应用场景和优缺点,以下是几种常见的实现异步的方法:
方法 | 描述 | 优点 | 缺点 |
---|---|---|---|
线程(Thread) | 通过创建新线程来执行任务 | 简单直接,易于理解 | 资源消耗大,频繁创建和销毁线程效率低 |
线程池(ExecutorService) | 使用线程池管理线程,重用线程资源 | 提高资源利用率,避免频繁创建销毁线程 | 需要手动管理线程池生命周期 |
Future与Callable | 通过Callable接口和Future对象获取异步执行结果 | 可以获取任务执行结果,支持异常处理 | 获取结果时可能阻塞,需要手动管理线程和任务生命周期 |
CompletableFuture | Java 8引入,支持链式调用和组合操作 | 功能强大,易于组合多个异步操作,非阻塞 | 学习曲线较陡峭,API相对复杂 |
Spring @Async注解 | 在Spring框架中使用@Async注解实现异步 | 简化异步编程,与Spring集成良好 | 需要配置线程池,依赖于Spring环境 |
详细实现方式
线程(Thread)
在Java中,最简单的异步编程方式就是直接创建一个新的线程来执行任务,这种方式适用于简单的异步需求,但不适合高并发或复杂的异步场景。
public class AsyncThread extends Thread { @Override public void run() { System.out.println("当前线程名称: " + this.getName() + " , 执行线程名称: " + Thread.currentThread().getName() + " -hello"); } }
线程池(ExecutorService)
使用线程池可以避免频繁创建和销毁线程的开销,提高系统资源的利用率,Java提供了Executors
工厂类来创建不同类型的线程池。
private ExecutorService executor = Executors.newCachedThreadPool(); public void fun() throws Exception { executor.submit(new Runnable() { @Override public void run() { try { // 模拟耗时操作 Thread.sleep(10000); System.out.print("睡够啦~"); } catch (Exception e) { throw new RuntimeException("报错啦!!"); } } }); }
Future与Callable
Callable
接口允许任务返回结果,并通过Future
对象来获取结果,这种方式适用于需要获取异步执行结果的场景。
public void futureTest() throws Exception { System.out.println("main函数开始执行"); ExecutorService executor = Executors.newFixedThreadPool(1); Future<Integer> future = executor.submit(new Callable<Integer>() { @Override public Integer call() throws Exception { System.out.println("===task start==="); Thread.sleep(5000); System.out.println("===task finish==="); return 3; } }); // 这里需要返回值时会阻塞主线程 // Integer result = future.get(); System.out.println("main函数执行结束"); System.in.read(); }
CompletableFuture
CompletableFuture
是Java 8引入的一个强大的异步编程工具,支持链式调用和组合操作,能够实现非阻塞的异步编程。
CompletableFuture<Long> completableFuture = CompletableFuture.supplyAsync(() -> factorial(number)); while (!completableFuture.isDone()) { System.out.println("CompletableFuture is not finished yet..."); } long result = completableFuture.get();
Spring @Async注解
在Spring框架中,可以使用@Async
注解来实现异步方法,首先需要在启动类上添加@EnableAsync
注解,并配置一个线程池。
@EnableAsync @SpringBootApplication public class StartApplication { public static void main(String[] args) { SpringApplication.run(StartApplication.class, args); } } @Configuration @Slf4j public class ThreadPoolConfiguration { @Bean(name = "defaultThreadPoolExecutor", destroyMethod = "shutdown") public ThreadPoolExecutor systemCheckPoolExecutorService() { return new ThreadPoolExecutor(3, 10, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(10000), new ThreadFactoryBuilder().setNameFormat("default-executor-%d").build(), (r, executor) -> log.error("system pool is full!")); } } @Service public class AsyncServiceImpl implements AsyncService { @Async("defaultThreadPoolExecutor") public Boolean execute(Integer num) { System.out.println("线程: " + Thread.currentThread().getName() + " , 任务: " + num); return true; } }
FAQs
Q1: CompletableFuture和Future有什么区别?
A1: CompletableFuture
是Future
的增强版,提供了更多的API来支持链式调用、组合操作和非阻塞的异步编程,而Future
只能通过get()
方法阻塞等待结果,且不支持链式调用。
Q2: 如何在Spring中使用@Async注解?
A2: 在Spring中使用@Async
注解需要先在启动类上添加@EnableAsync
注解,并配置一个线程池,然后在需要异步执行的方法上添加@Async
注解,并指定线程池的名称(
原创文章,发布者:酷盾叔,转转请注明出处:https://www.kd.cn/ask/55996.html