1.在SpringBoot中使用logback优化异常堆栈的源码输出
2.AJDK-AOT静态编译
3.å
³äºJAVAä¸çStack.pop()
4.ListenableFuture源码解析
在SpringBoot中使用logback优化异常堆栈的输出
一、背景
在我们在编写程序的源码过程中,无法保证自己的源码代码不抛出异常。当我们抛出异常的源码时候,通常会将整个异常堆栈的源码信息使用日志记录下来。通常一整个异常堆栈的源码黄金通道主图指标源码信息是比较多的,而且存在一些没用的源码信息。那么我们如何优化一些异常堆栈的源码信息打印,过滤掉不必要的源码信息呢?
二、需求1、源码现有的源码异常堆栈信息2、我们想优化成如下三、源码使用的源码技术1、此处我们是源码在SpringBoot中使用logback来实现日志的打印。 2、源码奇迹 源码 unity默认情况下,重写异常堆栈的打印比较复杂,此处我们采用第三方实现 ogstash-logback-encoder 来实现。
3、那么此处我们就采用 ogstash-logback-encoder 的 ShortenedThrowableConverter来实现。这个可以在以json格式的日志输出中使用,也可以使用到非json格式的日志中使用。我们将会用在以非json格式日志的输出。
四、技术实现1、引入依赖<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--?引入此jar包,可以将日志以json的格式输出,可以简化异常信息的输出?--><dependency><groupId>net.logstash.logback</groupId><artifactId>logstash-logback-encoder</artifactId><version>7.1.1</version></dependency>注意: 使用logstash-logback-encoder有一些依赖项,我当前使用的同步听源码依赖项如下:
1、如果发生了异常2、jdk的版本依赖版本不同,可能依赖的版本也不一样,推荐查看官方网址:/post/
AJDK-AOT静态编译
Go语言受到青睐于云上新应用,主要因其运行时无依赖,静态编译的程序启动速度快,无需JIT预热。
Java的静态编译技术作为激进的AOT技术,通过独立编译阶段将Java程序转化为本地代码,运行时不需传统Java虚拟机和运行时环境,仅需操作系统类库支持。
静态编译技术使Java语言与原生native程序“合体”,将Java程序编译为自举的具有Java行为的原生native程序,兼备Java程序与原生native程序的上传源码 域名优点。
Java编译流程包括前端编译、即时编译(JIT编译)与静态提前编译(AOT编译)。
前端编译将Java源码(.java)转化为Class文件(.class),实现程序转化为满足JVM规范的功能,优化侧重于程序编码,编译为Class文件可直接给JVM解释器执行,省去编译时间,加快启动速度。
后端编译(JIT编译)通过JVM内置的即时编译器,在运行时将Class文件字节码编译成本地机器码,优化程序运行性能,提高执行效率。
静态提前编译(AOT编译)程序运行前,直接将Java源码编译成本地机器码,dede 大气源码优点在于启动速度快,缺点是静态编译后性能优化受限。
静态编译器如JAOTC、GCJ、Excelsior JET、ART等,尤其是ART虽然主要通过AOT编译支持Java运行,但仍然存在解释器。
目前Java体系主要采用前端编译+JIT编译方式,如JDK中的HotSpot虚拟机,通过前端编译生成Class文件,启动时解释执行以节省时间,运行中通过JIT编译优化热点代码提高执行效率。
JIT编译与AOT编译比较,JIT吞吐量高,有运行时性能加成,执行更快,但启动速度较慢,需要时间与调用频率触发分层机制;AOT编译内存占用低,启动速度快,无运行时性能加成,不能动态优化。
Java 9引入AOT编译,能将class文件直接编译成可执行二进制文件。
在JVM团队与SOFAStack团队合作下,AJDK实现静态编译的落地,将应用启动时间从秒优化至3.8秒,双十一期间应用运行稳定,无故障,GC停顿时间在毫秒,内存占用和RT响应与传统Java应用持平,启动时间降低%。
综上所述,静态编译在稳定性、资源占用、RT响应等方面指标与传统Java应用基本持平,启动时间显著缩短。
å ³äºJAVAä¸çStack.pop()
å¨JAVAä¸,æStringå½åäºä¸ä¸ªé常åºæ¬çæ°æ®ç±»å,以è³äºä»»ä½ç±»åé½å¯ä»¥è½¬å为String
ä¸ç¥éä½ å¬æ²¡å¬è¿è¿å¥è¯:ä¸ç©ç对象
å¨JAVAéææçç±»é½æ¯ç»§æ¿èªOBJECTç±»,èOBJECTç±»ä¸æä¸ä¸ªæ¹æ³æ¯toString()å°±æ¯è¿åæ¹OBJECTçå符表示,ä¸é¢æ¯JDKä¸çæºç
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
è¿æå°±æ¯å¨JAVAä¸å¦æéå°äºå°ä¸ä¸ªç±»è½¯å为Stringæ¶,è¿ä¸ªç±»ä¼èªå¨è°ç¨toString()æ¹æ³
å¦
class Test{
String name;
public String toString(){
return "aaaa";
}
}
public class Test1 {
public static void main(String[] args) {
System.out.println(new Test());
}
}
è¿è¡å°è¾åº"aaaa"
ListenableFuture源码解析
ListenableFuture 是 spring 中对 JDK Future 接口的扩展,主要应用于解决在提交线程池的任务拿到 Future 后在 get 方法调用时会阻塞的问题。通过使用 ListenableFuture,可以向其注册回调函数(监听器),当任务完成时,触发回调。Promise 在 Netty 中也实现了类似的功能,用于处理类似 Future 的场景。
实现 ListenableFuture 的关键在于 FutureTask 的源码解析。FutureTask 是实现 Future 接口的基础类,ListenableFutureTask 在其基础上做了扩展。其主要功能是在任务提交后,当调用 get 方法时能够阻塞当前业务线程,直到任务完成时唤醒。
FutureTask 通过在内部实现一个轻量级的 Treiber stack 数据结构来管理等待任务完成的线程。这个数据结构由 WaitNode 节点组成,每个节点代表一个等待的线程。当业务线程调用 get 方法时,会将自己插入到 WaitNode 栈中,并且在插入的同时让当前线程进入等待状态。在任务执行完成后,会遍历 WaitNode 栈,唤醒等待的线程。
为了确保并发安全,FutureTask 使用 CAS(Compare and Swap)操作来管理 WaitNode 栈。每个新插入的节点都会使用 CAS 操作与栈顶节点进行比较,并在满足条件时更新栈顶。这一过程保证了插入操作的原子性,防止了并发条件下的数据混乱。同时,插入操作与栈顶节点的更新操作相互交织,确保了数据的一致性和完整性。
在 FutureTask 中,还利用了 LockSupport 类提供的 park 和 unpark 方法来实现线程的等待和唤醒。当线程插入到 WaitNode 栈中后,通过 park 方法将线程阻塞;任务执行完成后,通过 unpark 方法唤醒线程,完成等待与唤醒的流程。
综上所述,ListenableFuture 通过扩展 FutureTask 的功能,实现了任务执行与线程等待的高效管理。通过注册监听器并利用 CAS 操作与 LockSupport 方法,实现了在任务完成时通知回调,解决了异步任务执行时的线程阻塞问题,提高了程序的并发处理能力。