上次介绍了如何写一段代码造成 StackOverflow
,今天来玩一下,看如何写一段代码造成死锁
首先我们需要明确一下什么是死锁,造成死锁需要满足哪些条件,知道这些就可以轻松写出一段死锁代码了
死锁 是指两个或两个以上的进程(线程)在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁 状态或系统产生了死锁,这些永远在互相等待的进程称为死锁 进程(线程)。 ---- 百度百科
产生死锁的必要条件:
预防死锁方法:
通常的死锁的示例都是两个锁,多个资源导致的死锁,你有没有想过一个资源也会导致死锁,如何使用一个锁造成死锁呢?思考一下再看下面的代码
private static readonly object Lock = new object();
public static void Test()
{
lock (Lock)
{
Task.Run(TestMethod1).Wait();
}
}
private static void TestMethod1()
{
lock (Lock)
{
Console.WriteLine("xxx");
}
}
在
Test
这个方法中首先获取锁,获取锁成功之后调用另外一个线程去调用TestMethod1
方法,而TestMethod1
方法中会再次尝试获取锁,此时因为锁已经被Test
方法获取而且并没有释放,所以会一直获取不到锁从而造成死锁
其实这种情况还有很多变形,比如说 lock(this)
/lock("lockedString")
这种都是比较危险的,所以不推荐使用,我们使用上面的示例做一个变形,使用 lock("lockedString")
来测试一下
public static void Test()
{
lock ("Lock")
{
Task.Run(TestMethod1).Wait();
}
}
private static void TestMethod1()
{
lock ("Lock")
{
Console.WriteLine("xxx");
}
}
这样也会造成死锁,因为 lock 的 string 实际上是同一个引用,字符串池(string intern),所以类似于上面的示例,相当于是一个锁,对于 lock(this)
也是类似的,所以通常 lock
是不推荐 lock(this)
/lock("string")
这些写法的,对于不同的资源要使用不同的 lock
,这样就可以避免上面这个示例的这种情况
使用锁的一些注意事项:
private readonly object _locker = new object();
,是否使用 static
根据需要添加,多个资源有关联时,小心死锁的情况,一次全部分配,任意一个资源分配失败释放另外一个锁以避免死锁在 SQL Server 中会有一个独立的死锁检测的进程,如果发生死锁的情况,会有一个事务会被选择为牺牲品来解决死锁的问题
在通过 Redis
实现分布式锁的时候,通常会指定一个锁的过期时间,过期时间通常是为了避免获取锁成功的系统突然宕机导致锁一直在锁定状态,从而导致其他服务获取锁的时候一直获取失败,除此之外,通常还会指定一个最大等待时间,如果别的服务获取到锁了,正在操作,那么会等待锁释放,但是为了避免死锁,如果长时间获取不到锁的话就会放弃获取锁,直接返回获取锁失败。
除此之外你还了解哪些使用锁的注意事项和避免死锁的常用方法呢,欢迎补充,如果文中有误,欢迎指出,万分感谢。
Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8