One Trick Per Day

简介: 初始化Map宜预估容量,避免扩容开销;禁用Executors创建线程池,防止OOM,推荐手动定义参数或使用Guava;Arrays.asList返回不可变列表,禁止修改操作;遍历Map优先使用entrySet或forEach;SimpleDateFormat非线程安全,建议用ThreadLocal或Java8新时间API;并发更新记录需加锁,推荐乐观锁配合version机制。

One Trick Per Day
1.初始化Map大小并非用多少指定多少
初始化Map并非用多少初始化Size是多少,建议使用Guava,避免扩容引起的动荡()
说明
如:Map map = new HashMap<>(1); 在具体使用时,并非size=1,而是最近的2的幂等,如1实际是2,3实际是4,9实际是16
使用方法
依赖gvaua:Map map = Maps.newHashMapWithExpectedSize(7);
手动声明:Map map = new HashMap<>(实际存储个数 / 0.75 + 1);
2.线程池初始化严禁使用Executors
使用线程池时候,我们可能会使用下面四个场景,这在alibaba代码规范中都是明令禁止的
我们先来一个简单的例子,模拟一下使用 Executors 导致 OOM 的情况。
通过指定 JVM 参数:-Xmx8m -Xms8m 运行以上代码,会抛出 OOM:
以上代码指出,ExecutorsDemo.java 的第 16 行,就是代码中的 executor.execute(new SubThread());。
通过上面的例子,我们知道了 Executors 创建的线程池存在 OOM 的风险,那么到底是什么原因导致的呢?我们需要深入 Executors 的源码来分析一下。其实,在上面的报错信息中,我们是可以看出蛛丝马迹的,在以上的代码中其实已经说了,真正的导致 OOM 的其实是 LinkedBlockingQueue.offer 方法。
如果读者翻看代码的话,也可以发现,其实底层确实是通过 LinkedBlockingQueue 实现的:
如果读者对 Java 中的阻塞队列有所了解的话,看到这里或许就能够明白原因了。Java 中 的 BlockingQueue 主 要 有 两 种 实 现, 分 别 是 ArrayBlockingQueue 和 LinkedBlockingQueue。ArrayBlockingQueue 是一个用数组实现的有界阻塞队列,必须设置容量。LinkedBlockingQueue 是一个用链表实现的有界阻塞队列,容量可以选择进行设置,不设置的话,将是一个无边界的阻塞队列,最大长度为 Integer.MAX_VALUE。这里的问题就出在:不设置的话,将是一个无边界的阻塞队列,最大长度为Integer.MAX_VALUE。也就是说,如果我们不设置 LinkedBlockingQueue 的容量的话,其默认容量将会是 Integer.MAX_VALUE。 而 newFixedThreadPool 中创建 LinkedBlockingQueue 时,并未指定容量。此时,LinkedBlockingQueue 就是一个无边界队列,对于一个无边界队列来说,是可以不断的向队列中加入任务的,这种情况下就有可能因为任务过多而导致内存溢出问题。上面提到的问题主要体现在 newFixedThreadPool 和 newSingleThreadExecutor 两个工厂方法上,并不是说newCachedThreadPool 和 newScheduledThreadPool 这两个方法就安全了,这两种方式创建的最大线程数可能是Integer.MAX_VALUE,而创建这么多线程,必然就有可能导致 OOM
正确使用:
这种情况下,一旦提交的线程数超过当前可用线程数时,就会抛出java.util.concurrent.RejectedExecutionException,这是因为当前线程池使用的队列是有边界队列,队列已经满了便无法继续处理新的请求。但是异常(Exception)总比发生错误(Error)要好。
但是部分alibaba作者更推荐使用guava创建对应的线程池,示例如下:
通过上述方式创建线程时,不仅可以避免 OOM 的问题,还可以自定义线程名称,更加方便的出错的时候溯源。
3.Arrays.asList之后不要调用修改操作
因为asList返回的实际是一个Arrays内部类,并没有实现集合的修改方法(add/remove/clear)// 当操作修改方法时,会报UnsupportedOperationException。
第一种情况:list.add("yangguanbao"); 运行时异常。
第二种情况:str[0] = "gujin"; 那么 list.get(0)也会随之修改。[涉及栈堆指针操作,修改数组的数据,导致同样引用该数据的list值被改变]
4.使用 entrySet 遍历 Map 类集合 KV
说明:keySet 其实是遍历了 2 次,一次是转为 Iterator 对象,另一次是从 hashMap 中取出key 所对应的 value。而 entrySet 只是遍历了一次就把 key 和 value 都放到了 entry 中,效率更高。
如果是 JDK8,使用 Map.foreach 方法。
正例:values()返回的是 V 值集合,是一个 list 集合对象;keySet()返回的是 K 值集合,是一个 Set 集合对象;entrySet()返回的是 K-V 值组合集合。
5.SimpleDateFormat不要定义为static
SimpleDateFormat 是线程不安全的类,一般不要定义为 static 变量,如果定义为static,必须加锁,或者使用 DateUtils 工具类。
正例:注意线程安全,使用 DateUtils。亦推荐如下处理:
Java
运行代码
复制代码
1
2
3
4
5
6
private static final ThreadLocal df = new ThreadLocal() {
@Override
protected DateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd");
}
};
说明:如果是 JDK8 的应用,可以使用 Instant 代替 Date,LocalDateTime 代替 Calendar,DateTimeFormatter 代替 SimpleDateFormat,官方给出的解释:simple beautiful strong immutable thread-safe。
6.并发修改同一记录时需要加锁
要么在应用层加锁,要么在缓存加锁,要么在数据库层使用乐观锁,使用 version 作为更新依据。
说明:如果每次访问冲突概率小于 20%,推荐使用乐观锁,否则使用悲观锁。乐观锁的重试次数不得小于 3 次

相关文章
|
7月前
|
人工智能 自然语言处理 安全
2025年AI数字人公司新力量,集之互动0.8秒急速响应,构筑AI数字人核心壁垒
集之互动深耕AI数字人领域,以0.8秒极速响应、全栈私有化部署和高逼真3D技术为核心,打造安全可控、实时交互的数字员工。赋能医疗、文旅、零售等产业,助力企业降本增效,构建可持续的数字资产,推动AI商业落地。
416 4
|
11月前
|
机器学习/深度学习 编解码 数据可视化
无线电信号调制【小波去噪】(Matlab&Python代码实现)
无线电信号调制【小波去噪】(Matlab&Python代码实现)
468 1
|
12月前
|
机器学习/深度学习 人工智能 安全
正式发布!一文总览《中国人工智能应用发展报告(2025)》
阿里云研究院联合央视频等机构发布《中国人工智能应用发展报告(2025)》,全面分析人工智能技术趋势与产业应用,涵盖六大技术创新、五类落地场景、四力评估体系及百个创业案例,提出“五位一体”发展建议,推动AI成为新质生产力的核心引擎。
8059 0
|
测试技术 API
在性能测试中,怎样设置合理的迭代次数?
在性能测试中,迭代次数的合理设置至关重要,它直接影响到测试结果的准确性和可靠性。
1022 57
|
7月前
|
运维 Devops 开发工具
生产环境缺陷管理
为解决大型团队多分支开发中bug管理混乱、人为疏漏导致生产事故的问题,我们基于go-git开发了分布式工具git-poison。它实现bug的追溯、查询与发布卡点,自动化同步“投毒-解毒”信息,阻塞带未修复bug的版本发布,降低协同成本,避免“重复翻车”。已集成至发布与运维平台,提升缺陷管理效率与系统稳定性。
|
7月前
|
Java 测试技术 Linux
生产环境发布管理
本文介绍大型团队如何通过自动化部署平台实现多环境(dev/test/pre/prod)发布管理,涵盖各环境职责、基于Jenkins+K8S的CI/CD流程、分支发布、日志排查(Skywalking/ELK),并对比传统部署与现代平台的差异,提升发布效率与系统稳定性。(238字)
|
机器学习/深度学习 编解码 算法
《深度剖析:生成对抗网络如何实现图像风格的细腻逼真迁移》
生成对抗网络(GAN)在图像风格迁移中展现出巨大潜力。GAN由生成器和判别器组成,通过对抗训练生成逼真图像。相比传统方法,GAN能自动学习深层特征,生成多样化、细腻的风格,并实现高效处理。关键技术如多尺度训练、注意力机制及损失函数优化进一步提升了效果。GAN已广泛应用于艺术创作、游戏开发和影视制作等领域,未来有望带来更多创新应用。
586 2
|
JSON Java 数据格式
微服务——SpringBoot使用归纳——Spring Boot中的全局异常处理——定义返回的统一 json 结构
本课主要讲解Spring Boot中的全局异常处理方法。在项目开发中,各层操作难免会遇到各种异常,若逐一处理将导致代码耦合度高、维护困难。因此,需将异常处理从业务逻辑中分离,实现统一管理与友好反馈。本文通过定义一个简化的JsonResult类(含状态码code和消息msg),结合全局异常拦截器,展示如何封装并返回标准化的JSON响应,从而提升代码质量和用户体验。
386 0
|
数据采集 人工智能 数据管理
数据管理进化论:DMS助力企业实现智能Data Mesh
Gartner分析师认为Data Mesh对企业提升数据价值交付效率具有重要意义,阿里云数据管理服务DMS给出了对于Data Mesh的核心思考,包括企业什么时候应该考虑实施Data Mesh,如何解决业务团队素养和意愿问题。结合这些思考,DMS提出了企业可行的落地策略,即企业应以数据价值不断提升为导向,基于元数据驱动的Fabric、AI等能力实现智能Data Mesh,最终形成分布式和集中化的动态平衡,以达到企业数据驱动的最佳状态。
2346 6
数据管理进化论:DMS助力企业实现智能Data Mesh
|
存储 虚拟化
使用DiskGenius工具来实现物理机迁移虚拟机,实现虚拟化
【9月更文挑战第1天】使用 DiskGenius 工具可将物理机迁移到虚拟机,实现系统与数据的虚拟化。此过程包括:安装 DiskGenius 和准备虚拟化平台;备份物理机数据;使用 DiskGenius 备份磁盘;在虚拟化软件中创建新虚拟机并导入磁盘备份;配置及调整虚拟机设置;测试性能并优化资源分配。这有助于测试、开发及系统管理。
2457 6