Discuz! Board

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 2|回复: 0

洞察使用 synchronized 解决多线程并发问题 - Java 战案例

[复制链接]

37万

主题

0

回帖

111万

积分

超级版主

Rank: 8Rank: 8

积分
1114225
发表于 7 天前 | 显示全部楼层 |阅读模式
在Java项目中,我们经常会遇到多线程并发问题,尤其是在生成仅有标识符的场景中。本文将结合际项目案例,详细讲解如何使用synchronized解决多线程并发导致的任务编号重复问题。

问题背景
在我们的项目中,有一个创建任务的功能。每次创建任务时,系统会根据当前时间(年月日时分秒)生成一个任务编号,代码如下:

StringtaskNum=LocalDateTimenow()format(DateTimeFormatterofPattern("yyyyMMddHHmmss"));
理论上,每次生成的任务编号应该是仅有的。然而,在高并发场景下,多个线程同时调用该接口时,可能会生成相同的任务编号,这显然是不合理的。如图



问题复现
为了验证问题,我添加了输出开始时间和结束时间,并且精确到毫秒,因为这个接口响应时间在100~300毫秒,如果精确到秒,出现在同一时间那是必然的,看如果是毫秒级别,能否就直接解决这个问题了,代码类似如下

**
??*创建任务-提交
??*
??*@paramdto创建任务提交的数据对象
??*@return
??*
??@Override
??@Transactional
??publicintaddTask(TaskCreateDTOdto,StringuserId){
Systemoutprintln("开始"+LocalDateTimenow()format(DateTimeFormatterofPattern("yyyyMMddHHmmssSSS")));
?
StringtaskNum=LocalDateTimenow()format(DateTimeFormatterofPattern("yyyyMMddHHmmssSSS"));
Systemoutprintln("任务编号:"+taskNum);
一些业务逻辑
Systemoutprintln("结束"+LocalDateTimenow()format(DateTimeFormatterofPattern("yyyyMMddHHmmssSSS")));
?
return1;
?}
启动项目,并用APIfox进行并发测试,如图可以看到,即使精确到毫秒级,还是会生成出相同的编号,这说明在高并发场景下,多个线程同时进入了该方法。



问题分析
问题的根本原因是多个线程在同一时间调用了该方法,导致生成的任务编号相同。为了解决这个问题,我们需要确保同一时间只有一个线程可以执行该方法。

解决方案
在Java中,synchronized关键字可以确保同一时间只有一个线程执行被修饰的方法。但需要注意的是,synchronized的有效性依赖于方法所在类的例作用域。



单例模式:如果类的作用域是单例(Spring默认),则可以直接使用synchronized修饰方法。



多例模式:如果类的作用域是多例,则需要额外处理(例如使用类锁或静态锁)。



在我们的项目中,通过输出thishashCode()验证了当前类是单例的:

Systemoutprintln("当前例哈希码:"+thishashCode());


如上图,可以看到,每此在方法中输出的this的哈希码都是一样的,表示当前的现类对象在整个程序中是单例的,因此直接在方法上加上synchronized即可解决此问题

验证结果
代码如下

@Override
??@Transactional
??publicsynchronizedintaddTask(TaskCreateDTOdto,StringuserId){
Systemoutprintln("开始"+LocalDateTimenow()format(DateTimeFormatterofPattern("yyyyMMddHHmmssSSS")));
?
StringtaskNum=LocalDateTimenow()format(DateTimeFormatterofPattern("yyyyMMddHHmmssSSS"));
Systemoutprintln("任务编号:"+taskNum);
一些业务逻辑
Systemoutprintln("结束"+LocalDateTimenow()format(DateTimeFormatterofPattern("yyyyMMddHHmmssSSS")));
?
return1;
?}
再次使用APIfox进行并发测试,结果如下:



每次生成的任务编号都是仅有的。



多个线程依次执行该方法,避免了并发问题。



如图



注意事项
虽然synchronized可以有效解决并发问题,但在高并发场景下,可能会带来性能瓶颈。因此,建议在以下情况下使用:



并发量较低:适合并发量较小的场景。



方法执行时间较短:适合执行时间较短的方法。



需要严格保证线程安全:适合对数据一致性要求较高的场景。



如果并发量较大或方法执行时间较长,可以考虑其他化方案,例如减小锁粒度、使用读写锁或锁编程。

结语
通过幽络源本文的案例,我们深入了解了如何使用synchronized解决多线程并发问题。如果你对Java多线程编程感兴趣,欢迎加入我们的学习交流群(Q群:307531422),获取更多源码、技术和创教程。



所以,我们应该了解幽络源带来的很多好处,吸收归纳总结,并加以利用。幽络源-免费源码,网络兼职,技术教程,项目服务一站式综合平台。https://www.youluoyuan.com/

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|足球新闻网

GMT+8, 2025-4-25 12:08 , Processed in 1.371945 second(s), 18 queries .

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表