小白真诚求问, Java web 开发究竟啥场景需要用到多线程各种天花烂醉锁?

2023-03-09 11:00:54 +08:00
 GraySoul

本人是个啥都会点的多栈开发。 最近在准备面试,看到 java 面试题里考各种并发各种锁,一脸懵逼。 我写了这么多年 web 就没用过多线程,感觉自己属实弱,我单纯地觉得,真有那么多耗时需求扔消息队列里不就行了么?现在 java web 到底都在开发啥玩意,为啥这些都是面试重点呢?

没别的意思,是真不懂。。想问问具体有哪些场景。别的语言的程序员朋友们也欢迎指教,我写其他语言的 web 也没用过。。。我可能就是传说中的 crud 工程师= =

11762 次点击
所在节点    程序员
107 条回复
zero47
2023-03-09 15:12:58 +08:00
@TtTtTtT
@cloudzhou
@shakeyo
没看到你们回复之前,我都怀疑骂面试已经是政治正确了。
14104chk
2023-03-09 15:21:15 +08:00
@GraySoul readis 缓存数据就是最好的场景。

A 、a1 查缓存没有数据,a2 去查数据库,a3 数据缓存到 redis ,a4 返回数据
B 、b1 数据库更新,b2 删掉缓存。

逻辑简单,想写好不轻松。
这里面最容易掉进去的陷阱是执行顺序这样 a1,a2,b1,b2,a3,a4
写完之后,你可以写一个验证程序,对 a1,a2,a3,a4,b1,b2 做排列组合,看最终结果和预期的对不对
rapperx2
2023-03-09 15:26:39 +08:00
@shakeyo 坐等 大佬给思路
14104chk
2023-03-09 15:27:30 +08:00
@cloudzhou 这主要是任务的调度,可以把任务做成多棵树。树 1:a ,树 2:c ->(b 、d)。 开始运行,或者每一个任务运行完之后,把所有树里面没有子节点,或者子节点全部运行结束的任务扔到线程池
zzzzz001
2023-03-09 15:29:11 +08:00
多线程你无时无刻都在用,只不过封装在框架里面
RainCats
2023-03-09 15:32:56 +08:00
最近用过多线程的场景:
1 )异步去调用消息服务发一些不重要的通知(短信、邮件),因为付费版 MQ 开 topic 要钱的
2 )导出 Excel 的时候如果数据量达到一定数量级,走多线程去渲染不同的 sheet
3 )导入数据的时候也可以通过多线程来加速一下
4 )某接口有一堆远程调用的时候可以通过多线程来加速一下,串行请求太慢了
Promtheus
2023-03-09 15:36:16 +08:00
应用场景其实就是在面试的时候,不过讲真,就算平时用不到也需要知道。因为不知道的东西是肯定不会用的。只有先学到了才会知道是不是要用。
GraySoul
2023-03-09 15:49:09 +08:00
@haython 确实写过 php ,但感觉这和业务场景和规模关系比较大,我 nodejs ,java 的后台业务也都写过,但真就没遇到啊。。。
b123405060
2023-03-09 15:50:27 +08:00
多线程示例 1. 数据入库的时候, 多个线程同时入库。2. 查询数据的时候, 多个线程同时查询, 最后进行汇总。 锁: 多个用户同时抢单的时候, 你不加锁, 那不是都抢到了! 在做删除任务的时候, 你不加锁, 双击删除的时候, 会删除两次(也算是解决幂等问题)。
14104chk
2023-03-09 15:51:39 +08:00
@shakeyo 简单点就是加锁 lock(/1)->lock(/2)->unlock(/2)->unlock(/1)
有一个优化点,不过要看你的业务允不允许。
删除、重命名、移动,这些都是改的文件的组织结构,不是文件本身。文件本身只有修改。
可以把所有文件都存在一个目录下,然后把目录结构存数据库,表结构类似(id,pid,name,deleted,file_path)。file_path 是真实的物理路径。id 、file_path 永远不变。
其它的 删除、重命名、移动 只需要在数据库里面改 pid,name,deleted
只有修改文件本身的时候,才需要加锁
修改 /1/2 的时候,允不允许删除 /1 ,这需要业务去确定,但不管允不允许,都不可以不用等待修改 /1/2 的锁
不过修改 /1/2 完的时候,用户可能发现目录已经改变或删除了,这需要在业务上给用户反馈
devswork
2023-03-09 15:53:46 +08:00
多线程的话,爬虫,现抓取到 URL list ,然后开启线程池,批量爬取+解析 DOM+存入数据库,如果一个一个跑,太慢了,多线程直接起飞。
锁,我们用到 redis 锁,比如某个 API ,一个用户在指定秒数内只能访问 1 次,那就用到 url+用户 id (或 token )组合 key 的锁,调用接口前判断锁,进而防止重复请求。
cloudzhou
2023-03-09 15:54:58 +08:00
@14104chk 能提到树,我觉得算 ok 一半了,就是实际实现,还是很考验的,我这个例子就是说明并发的存在和挑战
shakeyo
2023-03-09 16:11:01 +08:00
@14104chk 现在就是你说的这个方案,数据库只有文件目录结构的索引,路径枚举的方式存储
真实文件是存储到 oss 上的,这里讨论要用到锁的场景指的也是针对文件目录树的冲突
那你的思路跟我是一样的,操作子目录得一直向上锁定
再蹲一个更好的思路
shakeyo
2023-03-09 16:13:23 +08:00
@cloudzhou 你这个应该是要基于 dag 实现一个任务调度器
GraySoul
2023-03-09 16:16:07 +08:00
@14104chk a1,a2,b1,b2,a3,a4 这个过程的问题是 a4 返回的数据是过期的不是 b1 最新改的吧。好吧,这种严苛的实时性我们确实不需要呢。。。但这个怎么用 java 锁来解决呢?你把 A 的代码用锁给锁了保证了原子性,但 B 该怎么执行还是怎么执行。

所以这是不是需要用到分布式锁呢?这其实有点偏中间件了,中间件需要搞这些锁技术我很理解,但 java 写个 api 的业务场景我还是觉得用不到啥锁。。🙇
fkdog
2023-03-09 17:19:38 +08:00
一个任务集群节点,要保证一个时间点只有一台机器执行某个任务,那么加锁是最简单的处理方法。
你用队列的话,一个任务你得重复执行 N 次。还要做额外的去重操作。
tairan2006
2023-03-09 18:43:25 +08:00
你写个连接池也要用锁啊。。
NoString
2023-03-09 19:12:46 +08:00
作为练习时长四年半一线 CRUD 程序员 在以下场景使用锁或者多线程解决问题更丝滑简单,更多是在解决分布式系统中的 CAP 原则带来的问题
1.广告投放做预算
2.商城商品卖库存
3.多机器刷 Token
4.聚合 API
5.拉取报表数据
6.多请求合并
7.电商积分、优惠券消耗

上面的场景通过队列也能解决,但有些场景我们对一致性的要求并不是最终一致,队列带来的消息可靠问题和时延以及剥离事务并不一定适用,因地制宜很关键

面试中的锁脱离场景 比如让你讲讲 AQS 、讲讲 synchronized 、自旋锁、乐观、悲观锁就是八股性质更多,但掌握这些东西能更好的让你理解 mysql 的锁设计、java 的锁设计、以及线程池的底层设计。
546L5LiK6ZOt
2023-03-09 19:13:45 +08:00
看到很多人说并行处理 io 需要用多线程,其实 nio 出来很多年了,一个线程就能同时管理多个 fd ,大多数 io 相关的类库都会提供异步接口,例如 redis client ,kafka client ,apache http client ,dubbo ,es client 等都有异步接口,比开多线程同步调用性能会好点(用多线程还得评估线程数,麻烦)。也有些例外,例如 jdbc ,只有同步接口,所以并发操作数据库只能开多线程了。
GraySoul
2023-03-09 19:30:36 +08:00
好了 感谢大家 我意识到自己错了,我现在就去学各种天花乱坠锁,研究到最后我再去读读底层源码,我要卷的让面试官爹都不认识。他日我若面试成功,回来回馈家人们。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/922519

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX