标签:# Java

Java New Future CDS

什么是CDS?CDS即 Class-Data Sharing,类数据共享功能,该功能可以减少Java应用程序的启动时间和内存占用。 类数据共享功能有助于减少多个Java虚拟机之间的启动时间和内存占用,从JDK12开始,默认的CDS归档文件和JDK二进制文件预先打包,我是用的JDK为OpenJDK OpenJDK 64-Bit Server VM Zulu17.42+19-CA (build 17.0.7+7-LTS, mixed mode, sharing),是支持CDS的。 使用 训练应用程序 首先初始化一个标准的SpringBoot应用,使用 SpringBoot-3.3.0 + Java17 ├── pom.xml ├── src │   ├── main │   │   ├── java │   │   │   └── top │   │   │   └── imyzt │   │   │   └── learning │   │   │   └── cds │   │   │   └── Java12NewFuturesCdsApplication.java @SpringBootApplication public class Java12NewFuturesCdsApplication { public static void main(String[] args) { SpringApplication.run(Java12NewFuturesCdsApplication.class, args); } } 将其执行Maven打包成jar文件 ➜ mvn package -DskipTests=true 执行训练命令 ➜ cd target ➜ target ✗ java -Djarmode=tools -jar java12-new-futures-cds-0.0.1-SNAPSHOT.jar extract --destination application ➜ cd application ➜ application ✗ java -XX:ArchiveClassesAtExit=application.jsa -Dspring.context.exit=onRefresh -jar java12-new-futures-cds-0.0.1-SNAPSHOT.jar 训练完成后,application目录下,生成了一系列文件: ➜ application git:(master) ✗ tree . ├── application.jsa ├── java12-new-futures-cds-0.0.1-SNAPSHOT.jar └── lib ├── jackson-annotations-2.17.1.jar ├── jackson-core-2.17.1.jar ├── jackson-databind-2.17.1.jar ├── jackson-datatype-jdk8-2.17.1.jar ├── jackson-datatype-jsr310-2.17.1.jar ├── jackson-module-parameter-names-2.17.1.jar ├── jakarta.annotation-api-2.1.1.jar ├── jul-to-slf4j-2.0.13.jar ├── log4j-api-2.23.1.jar ├── log4j-to-slf4j-2.23.1.jar ├── logback-classic-1.5.6.jar ├── logback-core-1.5.6.jar ├── micrometer-commons-1.13.0.jar ├── micrometer-observation-1.13.0.jar ├── slf4j-api-2.0.13.jar ├── snakeyaml-2.2.jar ├── spring-aop-6.1.8.jar ├── spring-beans-6.1.8.jar ├── spring-boot-3.3.0.jar ├── spring-boot-autoconfigure-3.3.0.jar ├── spring-boot-jarmode-tools-3.3.0.jar ├── spring-context-6.1.8.jar ├── spring-core-6.1.8.jar ├── spring-expression-6.1.8.jar ├── spring-jcl-6.1.8.jar ├── spring-web-6.1.8.jar ├── spring-webmvc-6.1.8.jar ├── tomcat-embed-core-10.1.24.jar ├── tomcat-embed-el-10.1.24.jar └── tomcat-embed-websocket-10.1.24.jar 1 directory, 32 files 使用训练的缓存,在启动应用程序时,补充-XX:SharedArchiveFile参数即可。 ➜ application ✗ java -XX:SharedArchiveFile=application.jsa -jar java12-new-futures-cds-0.0.1-SNAPSHOT.jar 启动日志: Started Java12NewFuturesCdsApplication in 2.262 seconds (process running for 2.805) 对比不使用CDS缓存的启动日志: Started Java12NewFuturesCdsApplication in 4.464 seconds (process running for 5.341) 可以看出来,尽管只是一个空项目,但是相同配置情况下启动速度都有倍增。 结语 从上面的测试可以看出来,项目的启动速度是有成本的效率增长的,但同时也存在弊端,就是每次应用程序发生变更时,需要冲洗进行jsa文件的训练。 不管是native-jar还是CDS,都是Java在云原生时代解决应用启动过程慢的探索,在应用的自动扩容领域,还是有不少的应用场景。 参考 Spring Boot 3.3.0 新特性| 使用 CDS 优化启动时间 CDS即Class-Data Sharing
Read More ~

ThreadPoolExecutor “非常用” 方法

平时在使用线程池时,更多关注到的是coreSize、maxSize、blockQueue、RejectedExecutionHandler这些参数,但在线程池监控领域,还需要关注到其他的一些方法。在此处做统一记录和备忘: public static void main(String[] args) { ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 5, 1, TimeUnit.MINUTES, new ArrayBlockingQueue<>(1024), new ThreadPoolExecutor.CallerRunsPolicy()); // 启动所有核心线程(预热) threadPoolExecutor.prestartAllCoreThreads(); // 启动一个核心线程 threadPoolExecutor.prestartCoreThread(); // 默认情况下构造器中的keepAliveTime指定的是非核心线程的空闲时间, 通过如下方法, 可以允许核心线程超时 threadPoolExecutor.allowCoreThreadTimeOut(true); // ⭐️ 动态线程池必备方法 // 启动后, 设置核心线程数量 threadPoolExecutor.setCorePoolSize(3); // 启动后, 设置最大线程数量 threadPoolExecutor.setMaximumPoolSize(10); // 已执行完的任务总数 threadPoolExecutor.getTaskCount(); // 获取工作队列剩余数量 threadPoolExecutor.getQueue().remainingCapacity(); } 后记 通过上面的代码可知,在运行过程中我们也是可以操作coreSize和maxSize的。那么如何才能实现对Queue的大小进行控制呢?目前开源届常用的是采取RabbitMQ中的VariableLinkedBlockingQueue来实现。
Read More ~

Hash冲突解决方法

什么是hash冲突? hash冲突就是在操作哈希表(散列表)的时候,不同的key值经过hash函数(散列算法)之后得到相同的hash值,那么一个位置没法放置两份value,这种情况就是hash冲突。 Hash冲突常用解决方法 开放地址法(open addressing) 简单来说就是通过计算出来冲突的hash值进行再次的运算,直到得到可用的地址,主要有以下3种: 线性探测再散列:发生冲突时,顺序查看哈希表下一单元是否可用,直到找到可用的单元 二次探测再散列:发生冲突时,以冲突的位置为中心向左右探测是否有可用单元 伪随机探测再散列:通过一组伪随机数列计算得到对应的单位位置 单独链表法 就是在哈希表中,针对相同的hash值使用链表的方式来存放 再Hash 提供多个hash函数,冲突时使用其他的hash函数再次运算 建立公共溢出区 建立一个溢出表,hash冲突的时候放入溢出表 Java中HashMap如何解决冲突 其实,Java中的HashMap采用的hash冲突解决方案就是单独链表法,也就是在hash表节点使用链表存储hash值相同的值 不过需要知道的是JDK8之后,如果链表长度超过8将会将链表转化为红黑树以便提高在hash冲突严重情况下的查询效率,也能够避免一定的hash碰撞攻击。
Read More ~