One Trick Per Day

简介: 本文分享Java开发中的6个实用技巧:合理初始化Map大小、避免Executors创建线程池引发OOM、Arrays.asList不可变性、高效遍历Map的entrySet方法、SimpleDateFormat线程安全问题及并发修改加锁策略,助你提升代码质量与系统稳定性。(238字)

聊天历史记录

暂无会话历史记录哦~

打开大学搜题酱APP在 「我的」页
点击「电脑端扫码」
下载大学搜题酱App
帮助
6

code
code
6

code
code
💡 快速上手
One Trick Per Day

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);
XML
复制代码
1
2
3
4
5


com.google.guava
guava
17.0

手动声明:Map map = new HashMap<>(实际存储个数 / 0.75 + 1);
2.线程池初始化严禁使用Executors
使用线程池时候,我们可能会使用下面四个场景,这在alibaba代码规范中都是明令禁止的
Java
运行代码
复制代码
1
2
3
4
5
6
7
8
9
10
11
// 创建一个单线程化的Executor[因为数量固定,可能会堆积大量请求,导致OOM]
private static ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();

// 创建一个固定数目线程的线程池[因为数量固定,可能会堆积大量请求,导致OOM]
private static ExecutorService fixedThreadPool = Executors.newFixedThreadPool(10);

// 创建一个可执行命令的单线程Executor[可能会创建大量的线程,导致OOM]
private static ExecutorService singleThreadScheduledExecutor = Executors.newSingleThreadScheduledExecutor();

// 创建一个可缓存的线程池(60S存活时间)[可能会创建大量的线程,导致OOM]
private static ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
我们先来一个简单的例子,模拟一下使用 Executors 导致 OOM 的情况。
Java
运行代码
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class ExecutorsDemo {
private static ExecutorService executor = Executors.newFixedThreadPool(15);
public static void main(String[] args) {
for (int i = 0; i < Integer.MAX_VALUE; i++) {
executor.execute(new SubThread());
}
}
}
class SubThread implements Runnable {
@Override
public void run() {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
//do nothing
}
}
}
通过指定 JVM 参数:-Xmx8m -Xms8m 运行以上代码,会抛出 OOM:
Java
运行代码
复制代码
1
2
3
4
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
at java.util.concurrent.LinkedBlockingQueue.offer(LinkedBlockingQueue.java:416)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1371)
at com.hollis.ExecutorsDemo.main(ExecutorsDemo.java:16)
以上代码指出,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。亦推荐如下处理:
说明:如果是 JDK8 的应用,可以使用 Instant 代替 Date,LocalDateTime 代替 Calendar,DateTimeFormatter 代替 SimpleDateFormat,官方给出的解释:simple beautiful strong immutable thread-safe。
6.并发修改同一记录时需要加锁
要么在应用层加锁,要么在缓存加锁,要么在数据库层使用乐观锁,使用 version 作为更新依据。
说明:如果每次访问冲突概率小于 20%,推荐使用乐观锁,否则使用悲观锁。乐观锁的重试次数不得小于 3 次

油炸小波2023-12-05 21:083116
0
IP 属地北京
举报
分享到:
shuangjin

注册 7 天后即可参与评论 了解更多
1747字
语雀
关于语雀使用帮助数据安全服务协议English
油炸小波
微服务技术栈
搜索
Ctrl + J
首页
目录
大纲
1.初始化Map大小并非用多少指定多少
2.线程池初始化严禁使用Executors
3.Arrays.asList之后不要调用修改操作
4.使用 entrySet 遍历 Map 类集合 KV
5.SimpleDateFormat不要定义为static
6.并发修改同一记录时需要加锁
Adblocker

相关文章
|
云栖大会 开发者
收到阿里云【乘风者计划】博主证书和奖励
收到阿里云【乘风者计划】博主证书和奖励 2023年2月对我来说是一个很好的开端,因为我在1号就收到了阿里云寄给我的【乘风者计划】博主证书和奖励。好兆头啊! 我收到的是我获得的【技术博主】【星级博主】【专家博主】三个的奖品和证书,一快给我寄过来哒!
3213 2
收到阿里云【乘风者计划】博主证书和奖励
|
4月前
|
人工智能 NoSQL 前端开发
Chap03. SpringAI
SpringAI整合多款主流大模型,支持对话、函数调用与RAG等架构,提供统一API简化开发。通过ChatClient封装交互,结合Prompt工程、工具调用与知识检索,可快速构建智能客服、哄哄模拟器、ChatPDF等应用,并支持多模态与持久化扩展,助力AI应用高效落地。
|
4月前
|
监控 Java 测试技术
OOM排查之路:一次曲折的线上故障复盘
本文记录了一次线上服务因Paimon数据湖与RocksDB集成引发的三次内存溢出(OOM)故障排查全过程。通过MAT、NMT、async-profiler等工具,结合监控分析与专家协作,最终定位到RocksDB通过JNI申请堆外内存未释放的根源问题,并推动架构优化:由应用直写改为Flink统一入湖。分享排查思路与工具使用,为同类技术栈提供借鉴。
|
4月前
|
人工智能 前端开发 JavaScript
4.6 前端(Cursor)-页面布局
使用Sealos DevBox创建Vue项目,通过Cursor开发。执行`npm run dev`启动,访问公网地址即可预览。基于Vue3+ElementPlus实现“智学云帆”布局:顶部标题、右侧登录信息、左侧菜单,右侧动态页面。优化背景色、宽度及响应式,首页设计简洁大气,提升整体视觉体验。(238字)
|
4月前
|
敏捷开发 持续交付
阿里巴巴-云效
通过阿里云效平台实现高效研发协作:开通服务后,可进行需求管理,创建项目并协作更新任务,支持看板模式直观跟进进度;结合代码托管与自动化部署,完成代码提交、流水线构建与发布全流程,助力团队敏捷开发。(239字)
|
4月前
|
弹性计算 安全 Linux
阿里云免费云服务器及学生云服务器申请教程指南
阿里云继续推出免费学生云服务器与免费试用云服务器,其中学生云服务器最长可免费7个月(1个月首次领用+6个月免费续领),免费试用云服务器分为个人免费云服务器和企业免费云服务器,最长免费试用时长是3个月。下面小编来介绍一下阿里云免费云服务器及学生云服务器的申请教程。
|
存储 缓存 开发工具
HarmonyOS Next~HarmonyOS应用开发工具之AppGallery Connect
AppGallery Connect(AGC)是华为为HarmonyOS开发者提供的全生命周期服务平台,支持开发、测试、上架到运营全流程。其核心功能包括应用分发、云数据库、认证服务和云函数等,助力开发者提升效率、缩短开发周期。AGC采用分层架构设计,集成40+云端服务能力,覆盖170+国家/地区,支持全球化业务拓展。通过事件跟踪、异常监控等工具,帮助开发者优化性能与用户体验。未来,AGC将引入低代码开发、增强现实等新能力,助力构建高质量HarmonyOS应用。
1080 4
阿里云服务器多少钱一年学生价?学生免费领取教程
阿里云学生免费领云服务器教程:先领300元学生专享代金券,再用券支付云服务器订单,实现免费领取。亲测有效,快来试试!
|
存储 弹性计算 安全
阿里云服务器经济型e实例4核16G和8核32G特惠云服务器测评参考
阿里云有两款特惠云服务器——4核16G10M带宽和4核32G10M带宽,系统盘都是100G ESSD Entry,价格分别仅需70元1个月和160元1个月。那么,这两款云服务器到底性能如何?适用于哪些场景?是否值得购买?本文将全方位深入测评这两款特惠云服务器,并为您提供详细的购买建议。
|
9月前
|
Java Linux 网络安全
Linux云端服务器上部署Spring Boot应用的教程。
此流程涉及Linux命令行操作、系统服务管理及网络安全知识,需要管理员权限以进行配置和服务管理。务必在一个测试环境中验证所有步骤,确保一切配置正确无误后,再将应用部署到生产环境中。也可以使用如Ansible、Chef等配置管理工具来自动化部署过程,提升效率和可靠性。
828 13