
多线程以提高了平台资源的利用率并且增加了平台的处理能力。但是,并发执行同时也带给了新的难题——死锁。所谓的轮询就是多个线程因竞争资源而导致的一种互相期待,如果没有外力作用,这些线程都将能够再次执行
通常系统中拥有的不可剥夺资源,其数目不足以满足多个线程运行的还要,使得线程在 运行过程中,会因争夺资源而陷入僵局,如磁带机、打印机等。只有对不可剥夺资源的竞争 才也许形成死锁,对可丧失资源的竞争是不会引起死锁的。
线程在运行过程中,请求和传递资源的顺序不当,也相同会导致死锁。例如,并发线程 P1、P2分别保持了资源R1、R2,而线程P1申请资源R2,线程P2申请资源R1时,两者都 会毕竟所需资源被挤占而阻塞。
信号量使用不当也会导致宕机。线程间互相彼此等待别人发来的消息,结果也会促使这 些线程间能够再次向前推动。例如,线程A等待线程B发的消息java多线程死锁,线程B又在期待线程A 发的消息,可以看出线程A和B不是因为竞争同一资源,而是在期待别人的资源造成死锁。

产生死锁必须同时满足下列四个条件,只要其中任一条件不成立,死锁就不会发生。
互斥条件:线程要求对所分配的资源(如打印机)进行排他性控制,即在一段时间内某资源仅为一个线程所占有。此时若有其它线程请求该资源,则请求线程没法等待不丧失条件:线程所取得的资源在未使用完毕之前,不能被其它线程试图剥夺,即没法 由拿到该资源的线程自己来释放(只能是被动释放)请求和维持条件:线程尚未保持了大约一个资源,但又强调了新的资源请求,而该资源 已被其它线程占有,此时请求线程被阻塞,但对自己已取得的资源维持不放循环等待条件:存在一种线程资源的循环等待链,链中每一个线程已取得的资源同时被 链中下一个线程所请求。即存在一个处于期待状态的线程集合{Pl, P2, ..., pn},其中Pi等 待的资源被P(i+1)占有(i=0, 1, ..., n-1),Pn等待的资源被P0占有
在有些情况下死锁是可以避免的。三种用于防止死锁的技术:
加锁顺序加锁时限死锁检查

当多个线程必须同样的一些锁,但是根据不同的次序加锁,死锁就容易发生。
按照顺序加锁是一种有效的死锁预防措施。但是,这种方法必须事先知道所有可能会用到的锁,但总有些时候是能够预知的。
当一个线程在尝试获得锁的过程中达到了这个时限则该线程需要放弃对该锁进行请求。
若一个线程没有在给定的时限内顺利拿到所有必须的锁,则会进行回退并传递所有即将获取的锁,然后期待一段随机的时间再重试。这段随机的期待时间让其他线程有机会尝试获得同样的这种锁,并且让该应用在没有获得锁的之后可以再次运行。

需要注意的是,由于存在锁的超时,所以我们不能认为那种画面就必定是发生了死锁。也或许是因为获得了锁的线程(导致其他线程超时)需要很长的时间去完成它的任务。
此外,如果有特别多的线程同一时间去竞争同一批资源,就算有超时和回退机制,还是可能会导致很多线程重复地尝试但却一直得不到锁。如果只有两个线程,并且重试的超时时间设置为0到500毫秒之间,这种现象也许不会发生java多线程死锁,但是一旦是10个或20个线程情况就不同了。因为这种线程等待相同的重试时间的几率就高的多(或者比较接近以至于会出现问题)。
死锁检测是一个更好的死锁预防措施,它主要是对于这些不也许实现按序加锁而且锁超时也不可行的场景。
每当一个线程获取了锁,会在泛型和锁相关的数据结构中(map、graph等等)将其记下。除此之外,每当有线程请求锁,也应该记录在这个数据结构中。

当一个线程请求锁成功时,这个泛型可以递归锁的关系图说说能否有死锁出现。
那么当测试出死锁时,这些线程该做些什么呢?
一个可行的做法是传递所有锁,回退,并且期待一段随机的时间后重试。这个和简单的加锁超时类似,不一样的是唯有死锁已经出现了才回退,而不会是因为加锁的请求超时了。虽然有回退和期待,但是一旦有长期的线程竞争同一批锁,它们抑或会重复地死锁(编者注:原因同超时类似,不能从根本上减少竞争)。
一个更好的方案是给那些线程修改优先级,让一个(或几个)线程回退,剩下的轮询就像没出现宕机一样继续维持着他们必须的锁。如果赋予这种线程的优先级是固定不变的,同一批线程总是会拥有更高的优先级。为防止这个难题,可以在死锁出现的之后修改随机的优先级。
Linux公社的RSS地址:
本文永久更新链接地址:
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-130497-1.html
梦一场
对自己定位清晰的boy