djn*_*jna 14
如果两个条件成立,则可能出现死锁:你有多个theads,他们争夺多个资源.
你写多线程代码?您可以通过启动自己的线程来显式地执行此操作,或者您可以在一个框架中工作,其中线程是在您的视线之外创建的,因此您在多个线程中运行而无需在代码中看到它.
一个例子:Java Servlet API.你编写了一个servlet或JSP.您部署到应用程序服务器.有几个用户访问了您的网站,因此也访问了您的servlet.服务器可能每个用户都有一个线程.
现在考虑如果在为请求提供服务时需要获取某些资源会发生什么:
if ( user Is Important ){
getResourceA();
}
getResourceB();
if (today is Thursday ) {
getResourceA();
}
// some more code
releaseResourceA();
releaseResoruceB();
Run Code Online (Sandbox Code Playgroud)
在上面的设计示例中,考虑一个重要用户的请求到达时星期四会发生什么,并且或多或少同时发生不重要用户的请求.
重要用户的线程获得Resoruce A并且想要B.不太重要的用户获得资源B并且想要A.也不会释放他们已经拥有的资源...死锁.
如果您正在编写明确使用同步的代码,这实际上很容易发生.最常见的是,我发现在使用数据库时会发生这种情况,幸运的是,数据库通常会有死锁检测,因此我们可以找出我们犯了什么错误.
防止僵局:
很难想象它在现实中发生的频率(在生产代码中?在开发中?)并且无论如何都不会真正了解有多少代码容易受到攻击.(通常情况下,僵局只会在非常特殊的情况下发生.)
我见过几次,虽然最近看到的是Oracle驱动程序(根本不在数据库中),因为终结器在另一个线程试图获取连接的同时运行.幸运的是,我发现了另一个让我避免终结器运行的错误......
基本上死锁几乎总是由于试图获得一个锁(B)同时持有另一个锁(A)而另一个螺纹完全相同而反之亦然.如果一个线程正在等待B被释放,并且持有B的线程正在等待A被释放,则两个线程都不愿意让另一个继续.
确保始终以相同的顺序获取锁(并以相反的顺序释放它们),并且在大多数情况下应该能够避免死锁.
有些奇怪的情况你没有直接拥有两把锁,但这是基本原理.例如,在.NET中,您可以使用Control.Invoke工作线程来更新UI线程上的UI.现在Invoke等待更新处理后再继续.假设您的后台线程持有锁更新需要...再次,工作线程正在等待UI线程,但UI线程无法继续,因为工作线程持有锁.再次陷入僵局.
这是一种需要注意的模式.如果你确定只锁定你需要的地方,锁定你可以逃脱的一段时间,并记录所有代码的线程安全和锁定策略,你应该能够避免死锁.但是,与所有线程主题一样,说起来容易做起来难.
| 归档时间: |
|
| 查看次数: |
4450 次 |
| 最近记录: |