我很难用简单的话来解释线程中的“死锁”,所以请帮忙。有没有最好的示例可以说明“死锁”(比如在Java中),它是如何按步骤发生的,如何预防呢?但不要深入细节。我知道这就像是在要求两件相反的事情,但还是请教一下。如果你有任何并发编程的经验 —— 那就太好了!
我很难用简单的话来解释线程中的“死锁”,所以请帮忙。有没有最好的示例可以说明“死锁”(比如在Java中),它是如何按步骤发生的,如何预防呢?但不要深入细节。我知道这就像是在要求两件相反的事情,但还是请教一下。如果你有任何并发编程的经验 —— 那就太好了!
杰克和吉尔恰好同时想做一个三明治。两个人都需要一片面包,所以他们都去拿面包和刀。
杰克先拿到了刀,而吉尔先拿到了面包。现在杰克试图找到面包,吉尔试图找到刀,但是他们发现完成任务所需的工具已经在使用中。如果他们决定等待直到所需工具不再在使用中,他们将永远互相等待。死锁。
thread 1:
lock(a)
lock(b)
thread2:
lock(b)
lock(a)
Thrd 1 --- Lock A - atmpt lock on B -
\ / \
\ / \
\ / \
--- Lock A / --- wait for lock on B
Thrd 2--- Lock B - atmpt lock on A -
\ / \
\ / \
\ / \
--- Lock B / --- wait for lock on A
线程1开始运行,锁定A,执行一些操作,然后被线程2中断,线程2锁定B,执行一些操作并被中断,线程1尝试锁定B,但线程2已经锁定了B,所以线程1等待,并被线程2中断,线程2尝试锁定A,但线程1已经锁定了A,所以线程2也必须等待。
两个线程都在等待另一个线程释放它们正在尝试获取锁定的资源...
死锁
我更愿意用与电脑完全无关的术语来解释,因为这通常是传达思想的最佳方式。
我有一个五岁的儿子和一个三岁的女儿。两个孩子都想做同一本涂色书。
女儿拿起了彩色铅笔,而儿子拿起了涂色书。他们都不会放弃自己手里的东西,直到得到对方的东西。
这就是僵局。再简单不过了。
你的进程(或孩子)被卡在等待对方的状态中,并将继续无限期地等待,直到其他上级进程(如父亲)介入并打破僵局。
至少对于孩子们,你可以(有时)让其中一个理性地放弃他们的锁。但是这通常在计算机上是不可能的,因为进程除了等待资源外什么都不做(尽管有时候孩子也会进入这种状态)。
遵循一个规则将确保死锁不会发生:
遵循一些额外的规则将使您的线程不太可能相互减速,但请记住,上述规则应优先于所有其他规则:
另一种演示死锁的好方法是使用SQL Server。
使用不同隔离级别的事务,您可以演示一个事务将无限期地等待被另一个事务锁定的表。
这里的优点是,您可以使用SQL Management Studio进行演示。我过去曾在教授“介绍SQL Server”级别的培训课程时向人们解释死锁。
大多数参与者都对理论感到困惑,但当他们看到它实际发生时,一切(通常)就变得清晰了。
简而言之:未完成的事务A(具有显式表锁定)获取了一个显式表锁定。第二个事务B尝试从被事务A锁定的表中读取。事务B被死锁,直到事务A提交或回滚。
您可以通过创建两个单独的线程来轻松地在代码中解释这一点,这两个线程依次创建事务。希望能有所帮助。
想象一下,你和女友因为谁应该打开门离开房子而争吵。道歉的人将会打开门。她在等你道歉,你在等她道歉,结果这对夫妇永远不会离开房子,因为两个人都拒绝道歉。
想象一下,一个罪犯劫持了人质并要求赎金。你带着满满一箱钱出现了。
在罪犯得到钱之前,他永远不会释放人质。在你得到人质之前,你永远不会放出钱。僵局。
这里的类比关系是:
死锁是指两个线程相互等待,彼此都无法继续执行,直到另一个线程先执行完毕,因此两个线程都被卡住了。
死锁需要至少两个锁,并且两个线程都必须包含获取锁并等待释放锁的代码。
线程1持有锁A并想要锁B,所以它等待锁B被释放。
线程2持有锁B并想要锁A,所以它等待锁A被释放。
现在你有了一个死锁。两个线程都在等待锁,因此都没有在执行,所以两个线程都无法释放对方正在等待的锁。
死锁发生在你有两个不同的资源,两个不同的线程需要锁定它们才能使用。这些线程以相反的顺序锁定它们,因此执行变得不可能,直到其中一个线程放弃。
维基百科有一些很好的现实生活例子可以说明死锁。