V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
GraySoul
V2EX  ›  程序员

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

  •  2
     
  •   GraySoul · 2023-03-09 11:00:54 +08:00 · 11446 次点击
    这是一个创建于 386 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

    107 条回复    2023-03-11 09:59:21 +08:00
    1  2  
    xhldtc
        1
    xhldtc  
       2023-03-09 11:10:19 +08:00   ❤️ 2
    面试造火箭呗,你可以没用过,但是你得懂。面试的时候两个人都没有用过,你懂他不懂,你说招哪个人?大环境太卷没办法
    zjsxwc
        2
    zjsxwc  
       2023-03-09 11:15:03 +08:00
    爬虫,用线程开 n 个连接“攻击”同一个服务器接口。2333
    FawkesV
        3
    FawkesV  
       2023-03-09 11:22:14 +08:00   ❤️ 2
    我们这边有这样子的场景:可能存在大批量数据查询的时候,按数据量拆分多线程查询。
    例如有一个接口需要查询指定的 ID 数据信息,需要查询到数据中台。可能最多存在 1000 个 ID 。就拆分每次查询 20 个,使用线程池查询,再将数据组装在一起。
    li746224
        4
    li746224  
       2023-03-09 11:23:48 +08:00   ❤️ 1
    api 服务算 java web 吗?如果算的话,我开发过的里面好像就通知服务和生成报表的服务用到了多线程。
    xiangyuecn
        5
    xiangyuecn  
       2023-03-09 11:24:03 +08:00   ❤️ 3
    ???
    ???

    http 请求本身就是多线程,不是啥都会点,你这是啥也不会
    crysislinux
        6
    crysislinux  
       2023-03-09 11:24:54 +08:00 via Android   ❤️ 1
    web 开发感觉 Java 进程层面的锁不太用的上,除非你设计的就是单机程序,否则就是用分布式锁或者数据库层面的锁了。
    tool2d
        7
    tool2d  
       2023-03-09 11:25:58 +08:00   ❤️ 1
    "我写了这么多年 web 就没用过多线程",前端的 web worker 就是多线程啊,而且不用上锁,都是用 json 消息在线程之间传输数据的。

    别说 java ,任何语言锁多了后,维护都很复杂。
    roundgis
        8
    roundgis  
       2023-03-09 11:26:48 +08:00 via Android
    只是抽插數據庫那基本上用不上
    tool2d
        9
    tool2d  
       2023-03-09 11:28:16 +08:00   ❤️ 3
    @xiangyuecn "http 请求本身就是多线程,不是啥都会点,你这是啥也不会'

    http 请求可以不开线程的,网络请求本来就是非阻塞 IO ,不会阻挡后面代码正常执行。比如 nodejs 就是单线程。
    GraySoul
        10
    GraySoul  
    OP
       2023-03-09 11:31:27 +08:00   ❤️ 1
    @crysislinux @tool2d 我说的没用过多线程是指:在 web 场景直接使用各种锁来对共享数据做并发处理。

    原理上的多线程我懂,以及在数据库层面 web 框架层面的多线程应用我也大体都了解,我显然不是指这些底层场景。。

    @xiangyuecn 没错我啥都不会,感谢批评
    pierswu
        11
    pierswu  
       2023-03-09 11:31:52 +08:00
    这是在考察逻辑能力
    GraySoul
        12
    GraySoul  
    OP
       2023-03-09 11:34:28 +08:00
    @FawkesV 非常感谢提供具体场景,不过类似这样的场景我感觉就是不太涉及共享数据的冲突,完全就是开完线程之后把各自的结果一归拢,确实用不上面试上那些玩意。
    rqxiao
        13
    rqxiao  
       2023-03-09 11:34:28 +08:00   ❤️ 1
    多线程:线程池处理大批量需要 io 的任务 ;分布式锁:mq 消费幂等性,下单减库存的线程安全
    GraySoul
        14
    GraySoul  
    OP
       2023-03-09 11:35:27 +08:00
    @roundgis 好一个抽插,这是能播的么
    libook
        15
    libook  
       2023-03-09 11:37:24 +08:00   ❤️ 1
    面试是测试你水平上限的,所以肯定要问一些面试官认为代表水平上限的问题,只问 CRUD 谁都会,一百份简历只要 5 个人怎么办。

    知己知彼百战不殆,你只有摸清楚了面试官的思路,才能更好拿捏面试。
    ljrdxs
        16
    ljrdxs  
       2023-03-09 11:40:45 +08:00
    “真有那么多耗时需求扔消息队列里不就行了么?”

    公司里应该真是这样的。
    1 楼正解。面试造火箭。
    GraySoul
        17
    GraySoul  
    OP
       2023-03-09 11:41:00 +08:00
    @tool2d @xiangyuecn 可能指的是 web 容器针对每个请求都会建一个线程来处理。他要是说的是发起 http 请求,那到底谁不懂还真是个问题。。
    hhjswf
        18
    hhjswf  
       2023-03-09 11:45:26 +08:00   ❤️ 1
    消息队列不用买啊?你说用开源自建,那也要部署一套占用资源。能用 Java 解决你不用,再引入一个中间件依赖,这很好吗?
    xinhochen
        19
    xinhochen  
       2023-03-09 11:46:45 +08:00   ❤️ 1
    说一个场景:用户在页面订阅由 websocket 推送的数据,关闭页面后需要移除订阅关系。当用户打开多个页面或者不同客户端使用,对于这个订阅关系的维护就用到了锁。当然,这个锁可能是提前实现好的组件内部使用的,开发者可以不用关心。
    bugmakerxs
        20
    bugmakerxs  
       2023-03-09 11:47:33 +08:00   ❤️ 1
    1. 避免程序启动时环境初始化方法被调用多次
    2. 请求方超发导致消费者并发消费同一条消息
    3. 多并行任务全部结束后执行另一个任务

    用到的地方确实不多,不过确实有点用
    vaaagle
        21
    vaaagle  
       2023-03-09 11:48:19 +08:00
    比如,客户让你,将所有的项目一键打包成 excel 然后在生成压缩包最后还得附上一个这些项目的 excel 清单的时候
    ps:上面的人不懂拒绝掉,最后分到你手上
    buffzty
        22
    buffzty  
       2023-03-09 11:50:38 +08:00
    并发时会用到.
    1. 能不用锁就不用锁
    2. 锁的越少越好
    3. 小心死锁
    byte10
        23
    byte10  
       2023-03-09 11:50:40 +08:00   ❤️ 1
    真有那么多耗时需求扔消息队列里不就行了么? 那你怎么去消费这些队列呢,你肯定也是用多线程去消费吧。当然一些 mq 可以直接配置多线程的数量。

    多线程还是挺讲究的,最小核心数和最大的核心数,还有任务队列 queue 的数量限制,拒绝策略,都是有讲究的,不同场景下是不一样的设置。大多数业务可能触碰不到这部分,只是很多框架都集成这些多线程的设计。
    dqzcwxb
        24
    dqzcwxb  
       2023-03-09 11:57:38 +08:00
    现在有一个需求,你要请求 5 个第三方接口进行数据汇总,接口耗时分别为 1s 2s 3s 4s 5s 且无法从第三方获得优化
    常规阻塞执行需要 15s 多线程并行执行可以压缩到 5s
    把接口换成数据库换成其他服务调用,就是多线程的应用场景
    而锁就更简单了,需要保证强一致性 但是为了性能一般只追求最终一致性
    CAP:一致性( Consistency )、可用性( Availability )、分区容错性( Partition tolerance )保证 A 和 P 的情况下牺牲 C
    MoYi123
        25
    MoYi123  
       2023-03-09 12:31:28 +08:00   ❤️ 2
    web 开发里会下面这个就足够了

    lock.acquire()
    do sth
    lock.release()

    会用到什么 2-3 个锁套来套去, cas 之类, 先看看是不是自己的设计有问题.
    statumer
        26
    statumer  
       2023-03-09 12:33:10 +08:00
    @dqzcwxb #24 你说的这个场景是最基础的 map reduce ,调 api 就能实现。
    ajaxgoldfish
        27
    ajaxgoldfish  
       2023-03-09 12:39:54 +08:00 via Android
    写 demo 的时候用过一次,多个线程压测拿到结果静态变量+1 ,就用过一次
    GraySoul
        28
    GraySoul  
    OP
       2023-03-09 13:01:10 +08:00 via Android
    感谢各位的回复,看完之后我稍微没那么焦虑了。我看面试题后,是真的以为其他程序员写个 web 业务都各种上天花乱坠锁的,就我们业务简单个一比连个多线程都用不到。

    最常规的锁,最基本的多线程应用我是熟悉的,啥语言都写过,golang 的 goroutine 啥的也都搞过。对操作系统的进程、线程以及语言级别协程啥的都有基本认知。我问这个问题是真的自己在 web 业务里没用过。

    看了大家的回复,我觉得普通的 web 业务应该是用不了太多,但自己写框架或者底层库什么的应该会常用。学了就是自己的,不怕多学,只是对于我面个普通 web 开发要做这些面试题有点点困惑。既然是卷的问题,那也没啥好多说的,高考也是这么过来的的,学起来就是。
    rapperx2
        29
    rapperx2  
       2023-03-09 13:28:51 +08:00
    我写代码经常就会碰到,跟业务场景有很大关系
    GraySoul
        30
    GraySoul  
    OP
       2023-03-09 13:29:57 +08:00 via Android
    @MoYi123 这个确实简单,但我还是没想到啥场景会用。web 开发中常见共享资源就是数据库、中间件这些。他们有各自的锁机制。java 这边共享资源能是啥呢?我难道要在内存里搞个共享的 map ,让不同的请求修改?这怎么想怎么二。。。
    GraySoul
        31
    GraySoul  
    OP
       2023-03-09 13:31:40 +08:00 via Android
    @rapperx2 卧槽 求指教 能否举个例子🙇 就像我在 30 楼说的,写 web 业务,共享资源都是数据库、中间件什么的,各有各的锁机制。但 java 这个层面需要锁做啥真的没用过
    cloudzhou
        32
    cloudzhou  
       2023-03-09 13:36:03 +08:00
    如果写中间件,那么多线程就是基本知识了
    而一个好的框架,就是让开发者不需要过度考虑并发问题
    sbex
        33
    sbex  
       2023-03-09 13:43:32 +08:00   ❤️ 1
    以前觉得没啥,但认识了几个 sb 之后发现对于多线程与锁的机制了解这种东西,你可以不知道有多细,但是必须知道有这个东西。

    说多了都是泪,跟 sb 相处的日子。
    14104chk
        34
    14104chk  
       2023-03-09 13:44:04 +08:00   ❤️ 1
    想优化,多线程会用得很多
    中间件、数据库的锁只能管自身的事情,但如果中间件、数据库的操作要合并在一个事务里,就需要自己去做。JAVA 的锁可以保证单个进程里面的事务隔离性
    dqzcwxb
        35
    dqzcwxb  
       2023-03-09 13:44:11 +08:00
    @statumer #26 op 问的不就是基础?什么代码不是调 api?
    YepTen
        36
    YepTen  
       2023-03-09 13:55:42 +08:00   ❤️ 1
    和业务场景深度绑定。
    1. 批量下载文件,比如传个 List 参数。一个线程 for 循环那多慢啊。
    2. 批量入库,给你一批数据,不能 batchinsert 的时候,for 循环明显不行啊,多线程走起。
    3. 一些后台线程等
    cloudzhou
        37
    cloudzhou  
       2023-03-09 13:56:10 +08:00   ❤️ 1
    @GraySoul 给你一个我最近遇到现实例子:
    一个很复杂的工作 job ,对一个对象进行操作,比如同时进行 a 、b 、c 、d 处理
    同时之间这些处理逻辑,可能存在依赖关系,比如 a 完全可以独立运行,c 依赖 b 、d 完成之后才运行,等等

    要求:
    1. 尽量多并发执行,同时避免线程空等待
    2. 严格按照依赖关系运行,并发安全
    3. 最后有个等待动作,要求所有操作完成,job.wait

    如果更高要求:
    1. 是否可以中途中断,取消当前 /后续执行
    2. 某个操作异常处理如何,是否做到 继续 or 中断
    3. 每个处理逻辑,是否可以影响调度过程,比如跳到指定逻辑,或者跳过指定逻辑
    4. 有没有最大等待时间
    5. 是否可指定等待某个阶段完成就好了,不需要所有都明确完成
    6. 防止滥用资源,是否可以控制最大并发数

    想想,你要怎么设计
    GraySoul
        38
    GraySoul  
    OP
       2023-03-09 13:57:40 +08:00
    @14104chk 愿意付费咨询,求一个真实场景学习,请你一顿午饭 哈哈哈
    cloudzhou
        39
    cloudzhou  
       2023-03-09 13:59:53 +08:00
    @GraySoul 我这个就真的是真实场景
    adoal
        40
    adoal  
       2023-03-09 14:04:19 +08:00
    用面试排除掉你,录用比你牛叉很多倍的人,但他们干的是你也能干的活,因为从业的人太多了。
    TtTtTtT
        41
    TtTtTtT  
       2023-03-09 14:07:37 +08:00   ❤️ 1
    发生问题:并行处理多个 IO 任务,减少总等待时间
    解决方案:加入消息队列
    然后,产生了一大堆新的问题:消息队列的高可用和一致性,超时和 session 管理。

    就,明明是杀鸡,用 Java 能解决的事情,为啥要用牛刀呢。。
    GraySoul
        42
    GraySoul  
    OP
       2023-03-09 14:08:16 +08:00
    @cloudzhou 费心了,非常感谢,我工作中确实没遇到过这种场景。我有个问题是这个共享的对象具体是什么呢,是内存里的对象?从数据库里取回来的一个大的数据对象?由于很大,所以需要各种线程并发取操作?
    hervey0424
        43
    hervey0424  
       2023-03-09 14:08:17 +08:00
    @zjsxwc 我感觉平时写的程序和爬虫差不多, 多个线程攻击数据库
    cloudzhou
        44
    cloudzhou  
       2023-03-09 14:10:39 +08:00
    @GraySoul 不是这个对象大,是这个对象上面要填充的数据大,可能触发多个 rpc ,db 等
    Biluesgakki
        45
    Biluesgakki  
       2023-03-09 14:11:41 +08:00   ❤️ 4
    @roundgis 第一次见用“抽插”这个词来形容操作数据库的
    apples01
        46
    apples01  
       2023-03-09 14:16:27 +08:00
    @xiangyuecn 他意思是他自己写过的业务逻辑没有遇到过多线程
    yazinnnn
        47
    yazinnnn  
       2023-03-09 14:19:14 +08:00
    我觉得不会也没关系, 你能找到另外一条赛道来跑赢你的竞争对手就行, 比如用 stm 和结构化并发来处理并发编程
    levintrueno
        48
    levintrueno  
       2023-03-09 14:30:40 +08:00
    @cloudzhou 感觉,CompletableFuture 蛮符合的
    GraySoul
        49
    GraySoul  
    OP
       2023-03-09 14:36:49 +08:00
    @cloudzhou 噢噢,我大概明白了,这个场景是不是就是假设我有那么一个对象要返回给前端,但是这个对象里面的数据需要从多个数据源那里去获取,而且不同数据源获取到的数据之间有依赖关系,可能先从 A 数据源获取完了个 x ,传给 B 数据源才能获取 y ,等等。这个场景不考虑你说的更高要求,我个人感觉用不着啥锁,因为共享对象里面可以设置多个 key ,获取到不同数据往不同 key 里塞就好了,会涉及到冲突么?但这确实是多线程实践的一个好例子。再次感谢!这里面关于是否涉及对锁的应用,还望不吝赐教!
    shakeyo
        50
    shakeyo  
       2023-03-09 14:37:36 +08:00
    当前碰到一个网盘场景,刚好发出来看看大佬们的想法
    数据库中基于路径枚举以及邻近表的方式存储了一个文件目录结构
    当多个用户对某个文件夹以及子文件夹进行操作的时候,可能会导致冲突
    例如,用户 a 在 /1/2 文件夹下上传或者移入文件、文件夹
    用户 b 同时对 /1 移动或者 rename ,或者删除,此时很显然造成了冲突,如果不做任何处理,用户 a 将碰到部分文件上传失败
    简单的思路就是根据路径设计一套读写锁,如果写目录,则把当前文件往上全部加锁,其他操作发现有写锁要么等待,要么友好提示用户稍后再试
    hzzh
        51
    hzzh  
       2023-03-09 14:38:57 +08:00
    请教各位大佬,现在到底什么语言不卷,我三年前从 Java 转到 C#,下次换工作本来想提前准备下再找个 Java ,看诸位说的这么卷,那到底提前准备个啥方向会好点
    GraySoul
        52
    GraySoul  
    OP
       2023-03-09 14:39:19 +08:00
    @yazinnnn 学习了,听都没听过= = 其实我的赛道是接项目赚点小钱,感觉那些高大上的都和我不沾边。。。毕竟连并发都没咋写过,基本都靠框架和库就解决了,不知道以后这职业生涯要咋混下去了;)
    diagnostics
        53
    diagnostics  
       2023-03-09 14:40:27 +08:00   ❤️ 2
    丢消息队列你也要保证安全发布啊。。。

    生产者-消费者是异步了,你考虑过异步转同步的场景没? Thread Leak 考虑过没?

    公司业务大了,需求多了,各种问题就有了。

    假设你上异步编程,Reactive Programing ,里面的 Operator 如何工作,怎么用的线程清楚了吗?

    面试就是筛选你的能力,你的学习能力不能在面试中考核出来,如果可以那么你不会也没关系,因为你学的快。

    还搞不清楚,Golang 里面写 Raft 也用到了各种锁,这不是 Java 的问题
    cloudzhou
        54
    cloudzhou  
       2023-03-09 14:41:04 +08:00
    @levintrueno 肯定用 Future ,但是你按照我上面要求写一个,就发现很多小细节,能体现并发掌握如何
    cloudzhou
        55
    cloudzhou  
       2023-03-09 14:42:05 +08:00
    @GraySoul 依赖关系你怎么处理,等待怎么等待
    yazinnnn
        56
    yazinnnn  
       2023-03-09 14:49:14 +08:00   ❤️ 1
    @GraySoul
    并不是高大上, 无锁并发同样属于面试造火箭 工作拧螺丝的范畴, 基本上工作中会
    lock.lock
    try{

    }finally{
    lock.release
    }

    或者
    lock.withLock{
    }

    就够了

    stm 是面试唬人的, 工作中不可能让你真写
    haython
        57
    haython  
       2023-03-09 14:49:53 +08:00
    你肯定是写 php 的
    yangzhezjgs
        58
    yangzhezjgs  
       2023-03-09 14:51:15 +08:00   ❤️ 2
    后端并发一般用在中间件里,典型的几个场景:
    1.大量客户端同时发送请求,所谓的高并发,这里需要考虑如何处理大量的网络连接,以及处理协议,调用业务逻辑等,需要用到多线程。
    2.有状态的应用,典型的是数据库,缓存之类的涉及存储的组件,需要考虑多个用户同时写入发生错误,一般就会用涉及事务,会用到到锁或者 MVCC 之类的技术。
    3.也是类似上面的场景,如数据库之类的,会设置定时任务定期让后台线程进行资源回收,备份之类的操作也会涉及多线程。
    一般的业务场景中,需要多线程的场景都被框架或者组件内部封装好了,学习的主要目的是使用中间件的时候,理解为什么要这么设计,大多数需要真的写多线程,一般找不到现成的框架,需要真的自己写的时候,但是这种情况太少了
    wupher
        59
    wupher  
       2023-03-09 14:59:23 +08:00
    我自己在工作代码中实际碰到的:

    - 多任务调度,一般会结合线程组任务管理和楼主说的锁。(有些任务不允许并行,只能依次或者限量执行)

    - 多服务调用,用户 web call ,业务要调 A,B,C,D,E 然后根据不同的返回结果返回相异。顺序调用会超时且用户体验不好,需要异步并发调用。

    BTW: 这两种一般碰多了都会组中间件。
    tulongtou
        60
    tulongtou  
       2023-03-09 15:00:52 +08:00
    @tool2d 用 python ,就一把锁,完全不用考虑(狗头
    zero47
        61
    zero47  
       2023-03-09 15:12:58 +08:00
    @TtTtTtT
    @cloudzhou
    @shakeyo
    没看到你们回复之前,我都怀疑骂面试已经是政治正确了。
    14104chk
        62
    14104chk  
       2023-03-09 15:21:15 +08:00   ❤️ 1
    @GraySoul readis 缓存数据就是最好的场景。

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

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

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

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

    面试中的锁脱离场景 比如让你讲讲 AQS 、讲讲 synchronized 、自旋锁、乐观、悲观锁就是八股性质更多,但掌握这些东西能更好的让你理解 mysql 的锁设计、java 的锁设计、以及线程池的底层设计。
    546L5LiK6ZOt
        79
    546L5LiK6ZOt  
       2023-03-09 19:13:45 +08:00   ❤️ 1
    看到很多人说并行处理 io 需要用多线程,其实 nio 出来很多年了,一个线程就能同时管理多个 fd ,大多数 io 相关的类库都会提供异步接口,例如 redis client ,kafka client ,apache http client ,dubbo ,es client 等都有异步接口,比开多线程同步调用性能会好点(用多线程还得评估线程数,麻烦)。也有些例外,例如 jdbc ,只有同步接口,所以并发操作数据库只能开多线程了。
    GraySoul
        80
    GraySoul  
    OP
       2023-03-09 19:30:36 +08:00
    好了 感谢大家 我意识到自己错了,我现在就去学各种天花乱坠锁,研究到最后我再去读读底层源码,我要卷的让面试官爹都不认识。他日我若面试成功,回来回馈家人们。
    GraySoul
        81
    GraySoul  
    OP
       2023-03-09 19:33:58 +08:00
    @tairan2006 (大哭)连接池难道不是直接配置上就完事了么= =HikariCP 什么的,你意思我自己实现一个连接池? 我一个 crud 工程师就这么被你们逼上了开发中间件的悬崖上。。。
    GraySoul
        82
    GraySoul  
    OP
       2023-03-09 19:35:23 +08:00
    @546L5LiK6ZOt 我确实喜欢 vert.x 和 nodejs 的那种 feel ,就审美很一致= =
    GraySoul
        83
    GraySoul  
    OP
       2023-03-09 19:38:07 +08:00
    @NoString “上面的场景通过队列也能解决,但有些场景我们对一致性的要求并不是最终一致,队列带来的消息可靠问题和时延以及剥离事务并不一定适用,因地制宜很关键”

    感谢,你这段话是真正的解决了我很大的一个困惑点,可能就是我们浅薄的业务里强一致场景几乎没有。
    benzalus
        84
    benzalus  
       2023-03-09 20:16:14 +08:00
    看完帖子,学到不少。多线程自己写很少,用别人写的倒挺多
    rehoni
        85
    rehoni  
       2023-03-09 20:40:37 +08:00
    楼主估计跟我一样,一直在做 to b ,难度都在业务上,而非技术上。所以工作上基本对多线程的应用场景根本没有多少需求==,当然多线程还是得学,就当满足自己的好奇心、个人提升,最终实现薪资提升 O(∩_∩)O
    wxlwsy
        86
    wxlwsy  
       2023-03-09 20:40:38 +08:00
    极致压榨 CPU 性能需要多线程.
    现在各自框架搞起来显得多线程没啥用,但是本质还是多线程,只是框架替你做了而已.
    maigebaoer
        87
    maigebaoer  
       2023-03-09 20:49:03 +08:00 via Android
    重计算的,用多线程和多 CPU 进行并行,比如图片视频处理;重 IO 的,任务关联度又不高,可以用单线程 Async EventLoop ,比如 http 请求
    chuck1in
        88
    chuck1in  
       2023-03-09 21:11:56 +08:00
    这个其实是看体量的。

    如果你的项目业务比较大,用户比较,数据比较多,就很可能会用得上。
    甚至写代码的时候必须时时考虑这个问题,不然很容易就出生产事故了。

    如果你做的项目一般都是单机跑,功能上能用就行,这些其实就完全用不上。
    GraySoul
        89
    GraySoul  
    OP
       2023-03-09 21:13:57 +08:00
    @rehoni 啊对 你说到点子上了,这么多年过去了,我总感觉我和别人不一样。。。他们都在说什么。。。面试都在面什么啊这是,然后就各种被人鄙视。。。讲道理论聪明才智,我觉得我也没说差很多啊,咋就同样做了这么多年,就我啥都不会呢。。。
    hzxxx
        90
    hzxxx  
       2023-03-09 21:44:10 +08:00
    @tool2d BIO 不是阻塞 IO 吗? js 是异步 IO 模型,所以不会阻塞
    cp19890714
        91
    cp19890714  
       2023-03-09 22:14:32 +08:00 via Android
    我现在的项目中经常用。如果不会用,就很难发现哪里需要用。
    很多人,说起来这些都懂,然而在业务开发中,逻辑都摆到面前了,他也没发现这里有并发问题。原因就是不懂,他所谓的懂,只是知道个皮毛。
    tool2d
        92
    tool2d  
       2023-03-09 22:39:25 +08:00
    @hzxxx 我一直没搞明白,为什么网络需要设计成阻塞接口。

    非阻塞还能让代码继续干点的事情,一阻塞就什么都做不了了,只能傻等。
    leonshaw
        93
    leonshaw  
       2023-03-09 23:11:30 +08:00
    @tool2d
    阻塞式接口更直观。重点不是等 IO 时让代码做别的事,而是让 CPU 做别的事。理想情况下,线程开销足够小,就可以一直创建线程调用阻塞接口。事件循环到协程的封装也是为了用阻塞式的逻辑写异步代码。
    pkupyx
        94
    pkupyx  
       2023-03-09 23:36:49 +08:00
    锁的基本原理还是要理解,以及不加锁会出什么问题。
    分布式一致性的几种实现方式比锁重要。
    鸡架可能需要深入掌握一些小众的锁。
    blankmiss
        95
    blankmiss  
       2023-03-10 00:39:20 +08:00
    @cloudzhou completefuture 同时干活来填充吗
    xuanbg
        96
    xuanbg  
       2023-03-10 06:17:02 +08:00
    多线程不见得就要锁,只是多线程读写同一个数据需要锁。不是多线程很多时候也是有锁的,譬如数据库事务就是锁。

    多线程是为了充分利用 CPU 时间,而锁则是为了保证数据的一致性。两者并没有什么必然的联系。
    Narcissu5
        97
    Narcissu5  
       2023-03-10 09:13:06 +08:00
    @tool2d 有没有这么一种可能,服务器有多个核
    nekoneko
        98
    nekoneko  
       2023-03-10 09:30:50 +08:00
    比如说有一些资源, 一些线程会消费资源, 一些线程会添加资源, 消费添加的时候还有一些其他动作, 这时候不加锁你试试.
    nekoneko
        99
    nekoneko  
       2023-03-10 09:34:35 +08:00   ❤️ 1
    比如说我有一亿条数据要处理, 每处理 100000 条需要调一个通知方法, 计数器要不要加锁, 调方法要不要加锁.
    leaves615
        100
    leaves615  
       2023-03-10 09:59:23 +08:00
    你要求工资 2000 ,绝对没有这么多问题。
    1  2  
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2876 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 36ms · UTC 14:22 · PVG 22:22 · LAX 07:22 · JFK 10:22
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.