线程学习6——死锁
死锁
多线程中,常见的一种问题除了竞态条件外就是死锁。
那什么是死锁呢?死锁就是:是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。
那么为什么会产生死锁呢?
1.因为系统资源不足。
2.进程运行推进的顺序不合适。
3.资源分配不当。
学过操作系统的朋友都知道:产生死锁的条件有四个:
1.互斥条件:所谓互斥就是进程在某一时间内独占资源。
2.请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
3.不剥夺条件:进程已获得资源,在末使用完之前,不能强行剥夺。
4.循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
死锁演示:
为了演示死锁,在类MyThread中,实例化了两个对象,obj1,obj2,并写了两个方法:
DeadLock1先是锁定了obj1,接着锁定obj2;DeadLock2先是锁定了obj2,再锁定了obj1。
现在有可能的方法DeadLock1中的obj1的锁定会被解除。接着出现一次线程切换,DeadLock2()开始运行,并锁定obj2。
第二个线程现在等待obj1锁定的解除。因为他需要等待,所以线程调度器在此调度第一个线程,但第一个线程在等待obj2锁定的解除。
这两个线程现在都在等待,只要锁定块没有结束,就不会解除锁定。这是一个典型的死锁。
类MyThread:
using System.Threading;
namespace ConsoleApplication1
{
public class MyThread
{
private Object obj1 = new object();
private Object obj2 = new object();
public void DeadLock1()
{
while (true)
{
lock (obj1)
{
lock (obj2)
{
Console.WriteLine("我已经锁定obj2!");
}
}
}
}
public void DeadLock2()
{
while (true)
{
lock (obj2)
{
lock (obj1)
{
Console.WriteLine("我已经锁定obj1!");
}
}
}
}
}
}
入口程序Main:
static void Main(string[] args)
{
MyThread myThread = new MyThread();
Thread thread1 = new Thread(myThread.DeadLock1);
Thread thread2 = new Thread(myThread.DeadLock2);
thread1.Start();
thread2.Start();
}
结果是:程序运行了许多循环,不久就没有响应了。数据在控制台写入几次。死锁问题的发生频率也取决于系统配置,每次运行的结果都不同。
如何避免:
可以在应用程序的体系架构中,从一开始就设计好锁定顺序,也可以为锁定定义超时时间。