面试:“必然”引起“死锁”的一段代码。 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
1cming
V2EX    Java

面试:“必然”引起“死锁”的一段代码。

  •  
  •   1cming 2018-05-23 10:42:29 +08:00 9760 次点击
    这是一个创建于 2769 天前的主题,其中的信息可能已经有所发展或是发生改变。

    这个必然让我有点疑惑,A 等待 B,B 等待 A 这种还有意外会发生吗?求教。

    第 1 条附言    2018-05-24 09:54:36 +08:00
    大家可以看一下#15 @ryd994 还有 #13 @geelaw 还有 #20 @mashiro233 这几位朋友的回答,再次感谢大家。
    QK8wAUi0yXBY1pT7
        1
    QK8wAUi0yXBY1pT7  
       2018-05-23 10:53:10 +08:00
    建议多翻一下《操作系统》和语文书。
    zhengxiaowai
        2
    zhengxiaowai  
       2018-05-23 10:55:21 +08:00
    分分钟 100 个例子
    luojianxhlxt
        3
    luojianxhlxt  
       2018-05-23 12:09:47 +08:00
    数据库里面很多,代码倒是没咋接触过
    Arsenal16
        4
    Arsenal16  
       2018-05-23 12:32:56 +08:00
    老哥看一下 实战 Java 高并发程序设计 4.5 有关死锁的问题 那一章节
    百分百死锁啊, 讲的还是挺详细的.
    这里贴代码排版会有问题, 老哥你可以直接去看一下书
    ldd
        5
    ldd  
       2018-05-23 12:57:38 +08:00
    这个是肯定会引起死锁的,这种情况在多节点的 RAC 上见得比较多,比如需要同时更新多个表时,不同的业务对这几张表的更新顺序不一致,就容易引发死锁。

    不过像 Oracl 这样企业级的软件都会有自动的解锁行为,有个时间阈值,超过后就会牺牲掉一个事物,达到解锁目的。所以实际业务中几乎不会出现长时间的死锁。
    q397064399
        6
    q397064399  
       2018-05-23 13:09:35 +08:00
    死锁的四个必要条件
    0Y89tX3MgR4I
        7
    0Y89tX3MgR4I  
       2018-05-23 13:33:07 +08:00 via Android   6
    是不是我语文不好,看不懂楼主想表达什么
    1cming
        8
    1cming  
    OP
       2018-05-23 13:33:23 +08:00
    @Arsenal16 好的谢谢我下午看一下
    GuuJiang
        9
    GuuJiang  
       2018-05-23 13:43:56 +08:00
    methodA() {
    synchronized(lockA) {
    Thread.sleep(10000);
    synchronized(lockB) {
    ...
    }
    }
    }

    methodB() {
    synchronized(lockB) {
    Thread.sleep(10000);
    synchronized(lockA) {
    ...
    }
    }
    }

    拿去不谢
    1cming
        10
    1cming  
    OP
       2018-05-23 13:44:14 +08:00
    @Arsenal16 这里我刚才看了 他举的例子也并没有特别的地方 难道是我多想了?


    @hxd
    @zhengxiaowai
    @ldd
    @0Y89tX3MgR4I
    对方的原话大意是:写一个“必然”会出现死锁的一段代码,我面过很多人,他们写的都不是严格意义上的死锁,都被我挑出来很多刺。
    鉴于此,我在思考是否有代码之外比如 OS 上的一些考虑?
    1cming
        11
    1cming  
    OP
       2018-05-23 13:46:08 +08:00
    对方是某一线大厂资深级别的技术 leader,感觉事情并不简单,所以才会来 V 站一问,下午我会更新一下结果。
    startar
        12
    startar  
       2018-05-23 14:17:55 +08:00 via Android
    线程 1:
    锁 A
    锁 B
    干活
    释放 B
    释放 A

    线程 2:
    锁 B
    锁 A
    干活
    释放 A
    释放 B

    这样就会死锁啊
    geelaw
        13
    geelaw  
       2018-05-23 14:27:00 +08:00 via iPhone   2
    用睡眠并不会必然导致死锁,只是以非常高的概率导致而已。

    一个简单的方法是这样:线程 1 把自己的 handle 存在全局变量的 1 里,然后启动线程 2 并获得其 handle,然后等待这个 handle (等线程 2 结束);线程 2 的惟一工作是等待线程 1 的 handle。很容易证明,无论怎样调度,一定会进入死锁。

    在没有单进程多线程概念的操作系统(如传统 UNIX ),你需要通过进程的等待完成类似任务。
    ryd994
        14
    ryd994 &nsp;
       2018-05-23 14:49:33 +08:00 via Android
    非重入锁重入就是保证死锁
    ryd994
        15
    ryd994  
       2018-05-23 14:57:42 +08:00 via Android   4
    多线程的话可以用信号量
    1 锁 A,2 锁 B
    1 给 2 发信号,2 给 1 发信号
    等到收到信号,1 锁 B,2 锁 A
    因为各自没有取得锁前不会发出信号,因此收到信号就可以保证死锁
    信号量可以使用操作系统的信号量,也可以使用原子变量简单实现

    这不是一道考锁的题,而是一道考分布式系统事件排序的题

    @GuuJiang 如果因为进程调度,method B 被调度到 A 完成之后才执行呢?正常调度系统会考虑公平性,所以很难发生。但这并不是前提条件。
    roychan
        16
    roychan  
       2018-05-23 14:58:44 +08:00
    写个哲学家就餐问题不就 ok 了。。。
    John60676
        17
    John60676  
       2018-05-23 15:02:13 +08:00
    哲学家就餐 加一
    0Y89tX3MgR4I
        18
    0Y89tX3MgR4I  
       2018-05-23 15:04:12 +08:00
    @ryd994 嗯,两个锁和一个条件变量就好了
    nullcc
        19
    nullcc  
       2018-05-23 15:05:39 +08:00
    thread 1:
    acquire(A)
    acquire(B)

    thread 2:
    acquire(B)
    acquire(A)

    Bomb !!!
    mashiro233
        20
    mashiro233  
       2018-05-23 15:27:16 +08:00   1
    楼上的一些朋友回答的很好了。
    调度器的运作原理对应用层来说应该是未定义的。代码中启动 A,B 两个线程,调度器可以不保证 A 在 B 之前或者之后启动,启动了也不保证每个线程能用多少 cpu 时间。
    ryd994
        21
    ryd994  
       2018-05-23 15:39:21 +08:00 via Android
    @roychan
    @John60676 哲学家就餐只是可能死锁,并不能保证死锁。如果某个哲学家手特别快,在别人反应过来前就左右都抢到了呢?有调度器在,就不能忽略这种可能。

    @nullcc A 特别快,直接把两个锁都拿到了
    1cming
        22
    1cming  
    OP
       2018-05-23 15:55:03 +08:00
    @geelaw
    @ryd994
    感谢二位,这个是我想要的答案。
    zhangchioulin
        23
    zhangchioulin  
       2018-05-23 16:11:16 +08:00
    iOS 中 OSSpinLock 优先级反转也会死锁
    USNaWen
        24
    USNaWen  
       2018-05-23 16:47:22 +08:00
    互斥
    不可剥夺
    请求和保持
    循环等待
    tangweihua163
        25
    tangweihua163  
       2018-05-23 19:02:07 +08:00
    必然死锁,一个线程内才行,连续多次试锁同一资源?多个线程就不是必然
    zhengxiaowai
        26
    zhengxiaowai  
       2018-05-23 21:37:00 +08:00
    @1cming 一个很经典的案例:哲学家就餐问题
    Finest
        27
    Finest  
       2018-05-23 22:03:26 +08:00
    线程 A:
    l1.lock()
    while(true)
    l2.lock()

    线程 B:
    l2.lock()
    while(true)
    l1.lock()
    KIDJourney
        28
    KIDJourney  
       2018-05-23 22:40:37 +08:00
    l1 = lock()
    l1.lock()
    l1.lock()

    这不就死锁了。
    tempdban
        29
    tempdban  
       2018-05-23 22:55:46 +08:00 via Android
    上了一课
    ryd994
        30
    ryd994  
       2018-05-24 02:52:09 +08:00 via Android   1
    @KIDJourney 你这个就叫不可重入锁重入
    如果是重入锁,同一个线程锁两次是允许的
    另外也可以设置如果重入则报错
    jedihy
        31
    jedihy  
       2018-05-24 03:06:36 +08:00
    对,这不是考 OS,这是靠分布式系统与算法
    ebingtel
        32
    ebingtel  
       2018-05-24 09:11:27 +08:00
    @q397064399 对头 lz 描述的情况 只满足了一个
    lerosua
        33
    lerosua  
       2018-05-27 13:23:16 +08:00
    邮局寄个包裹给你, 要你身份证就能给你,但你的身份证就在包裹里~ 所以死锁了~
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     896 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 33ms UTC 18:51 PVG 02:51 LAX 10:51 JFK 13:51
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86