Java异步实现的N种方式

本文介绍了Java中实现异步编程的几种方式,包括Future、ListenableFuture、CallbackHell、CompleteableFuture和Reactor。详细阐述了每种方式的原理、优缺点及使用示例,帮助开发者更好地理解和运用Java异步编程。

背景

异步编程现在受到了越来越多的关注,尤其是在IO密集型的业务场景中,相比传统的同步开发模式,异步编程的优势越来越明显,本文介绍Java常见的实现方式;

Future

描述

java.util.concurrent.Future是JDK5引入的,用来获取一个异步计算的结果。可以使用isDone方法检查计算是否完成,也可以使用get阻塞住调用线程,直到计算完成返回结果,使用cancel方法停止任务的执行。

FutureTask.java是对Futre和Runnable最简单的实现,实现了run函数,所以可以直接执行,任务执行结束通过set()保存结果,setException()保存异常信息。通常配合executorService.submit()一起使用,ExecutorService中将任务包装成FutureTask执行execute();

样例

		@Test
????public?void?futureCallBackTest()?throws?InterruptedException,?ExecutionException?{
????????System.out.println(printThread("小明点餐"));
????????Future<String>?future?=?executorService.submit(()?->?{
????????????System.out.println(printThread("厨师开始炒菜"));
????????????Thread.sleep(2000);
????????????System.out.println(printThread(?"厨师炒好菜"));
????????????return?"饭菜好了";
????????});

????????String?result?=?future.get();
????????executorService.shutdown();
????????System.out.println(printThread(result?+?",小明开始吃饭"));
????}

运行结果

优缺点

  • 能获得异步线程执行结果

  • 无法方便得知任务何时完成

  • 在主线程获得任务结果会导致主线程阻塞

  • 复杂一点的情况下,比如多个异步任务的场景,一个异步任务依赖上一个异步任务的执行结果,异步任务合并等,Future无法满足需求

ListenableFuture

描述

Google并发包下的listenableFuture对Java原生的future做了扩展,顾名思义就是使用监听器模式实现的回调,所以叫可监听的future,通过addListener(Runnablelistener,Executorexecutor)方法添加回调任务。

要使用listenableFuture还要结合MoreExecutor线程池,MoreExecutor是对Java原生线程池的封装,比如常用的MoreExecutors.listeningDecorator(threadPool);修改Java原生线程池的submit方法,封装了future返回listenableFuture。

样例

@Test
????public?void?listenableFutureTest()?throws?InterruptedException,?ExecutionException?{
????????System.out.println(printThread("小明点餐"));
????????ListeningExecutorService?listeningExecutorService?=?MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor());
????????ListenableFuture<String>?listenableFuture?=?listeningExecutorService.submit(()?->?{
????????????System.out.println
### JAVA异步日志实现方法与示例代码 在Java中,可以通过多种方式实现异步记录日志。以下将详细介绍几种常见的实现方法,并提供相应的代码示例。 #### 方法一:使用Logback的异步Appender Logback框架提供了内置的异步Appender功能,可以轻松实现日志的异步记录。通过配置文件即可启用异步日志打印功能[^4]。 以下是Logback的配置文件`logback.xml`示例: ```xml <configuration> <!-- 定义同步Appender --> <appender name="ASYNC_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>logs/app.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>logs/app.%d{yyyy-MM-dd}.log</fileNamePattern> <maxHistory>30</maxHistory> </rollingPolicy> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <!-- 包装为异步Appender --> <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender"> <appender-ref ref="ASYNC_FILE"/> <queueSize>500</queueSize> <discardingThreshold>0</discardingThreshold> <includeCallerData>true</includeCallerData> </appender> <!-- 根Logger配置 --> <root level="info"> <appender-ref ref="ASYNC"/> </root> </configuration> ``` #### 方法二:使用Spring AOP结合异步任务工厂 通过Spring AOP和自定义的异步任务工厂,可以在业务逻辑中捕获异常并异步记录日志。这种方式适用于需要对特定操作进行日志记录的场景[^3]。 以下是实现代码示例: 1. **创建异步任务工厂**: ```java public class AsyncFactory { public static TimerTask recordException(ExceptionLog exceptionLog) { return new TimerTask() { @Override public void run() { SpringUtils.getBean(ExceptionLogService.class).saveExceptionLog(exceptionLog); } }; } } ``` 2. **定义切面类**: ```java @Aspect @Component public class LogAspect { @AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))", throwing = "e") public void logAfterThrowing(JoinPoint joinPoint, Throwable e) { ExceptionLog exceptionLog = new ExceptionLog(); exceptionLog.setClassName(joinPoint.getTarget().getClass().getName()); exceptionLog.setMethodName(joinPoint.getSignature().getName()); exceptionLog.setExceptionDetail(e.getMessage()); // 异步记录日志 Timer timer = new Timer(); timer.schedule(AsyncFactory.recordException(exceptionLog), 0); } } ``` #### 方法三:使用CompletableFuture实现异步日志记录 通过`CompletableFuture`可以手动实现日志的异步记录功能。这种方式适用于不依赖第三方框架的场景[^1]。 以下是代码示例: ```java import java.util.concurrent.CompletableFuture; public class AsyncLogger { public static void log(String message) { CompletableFuture.runAsync(() -> { try { // 模拟日志写入操作 Thread.sleep(100); System.out.println("Logged: " + message); } catch (InterruptedException e) { Thread.currentThread().interrupt(); System.err.println("Logging interrupted"); } }); } public static void main(String[] args) { log("This is an async log message."); System.out.println("Main thread continues execution..."); } } ``` ### 注意事项 -实现异步日志时,需确保线程安全,避免因多线程访问导致的数据不一致问题。 - 如果使用Logback的异步Appender,应合理设置队列大小(`queueSize`)以防止内存溢出。 - 对于复杂的业务场景,推荐结合AOP和异步任务工厂实现更灵活的日志记录功能[^3]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值