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

2018-05-23 10:42:29 +08:00
 1cming

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

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

不过像 Oracl 这样企业级的软件都会有自动的解锁行为,有个时间阈值,超过后就会牺牲掉一个事物,达到解锁目的。所以实际业务中几乎不会出现长时间的死锁。
q397064399
2018-05-23 13:09:35 +08:00
死锁的四个必要条件
0Y89tX3MgR4I
2018-05-23 13:33:07 +08:00
是不是我语文不好,看不懂楼主想表达什么
1cming
2018-05-23 13:33:23 +08:00
@Arsenal16 好的谢谢我下午看一下
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
2018-05-23 13:44:14 +08:00
@Arsenal16 这里我刚才看了 他举的例子也并没有特别的地方 难道是我多想了?


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

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

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

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

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

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

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

thread 2:
acquire(B)
acquire(A)

Bomb !!!
mashiro233
2018-05-23 15:27:16 +08:00
楼上的一些朋友回答的很好了。
调度器的运作原理对应用层来说应该是未定义的。代码中启动 A,B 两个线程,调度器可以不保证 A 在 B 之前或者之后启动,启动了也不保证每个线程能用多少 cpu 时间。

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

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

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

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

© 2021 V2EX