勇哥注:
《多线程安全》这个系列会持续写下去,它是我的一个弱点,有兴趣的朋友可以选择性看看。
下面源码运行后会发生死锁。
源码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
classA ca = new classA();
classB cb = new classB();
ca.show(cb);
cb.show(ca);
}
}
public class classA
{
//注意这里是public
public static readonly object lockobj = new object();
public void show(object lockobj)
{
for (int i = 0; i < 5; i++)
{
int k = i;
Task.Run(() =>
{
lock (this)
{
Console.WriteLine("ca...");
lock(lockobj)
{
Console.WriteLine($"{i},{k},classAstart...[{Thread.CurrentThread.ManagedThreadId}]");
Thread.Sleep(1000);
Console.WriteLine($"{i},{k},classAend...[{Thread.CurrentThread.ManagedThreadId}]");
}
}
});
}
}
}
public class classB
{
//注意这里是public
public static readonly object lockobj = new object();
public void show(object lockobj)
{
for (int i = 0; i < 5; i++)
{
int k = i;
Task.Run(() =>
{
lock (this)
{
Console.WriteLine("cb...");
lock (lockobj)
{
Console.WriteLine($"{i},{k},classBstart...[{Thread.CurrentThread.ManagedThreadId}]");
Thread.Sleep(1000);
Console.WriteLine($"{i},{k},classBend...[{Thread.CurrentThread.ManagedThreadId}]");
}
}
});
}
}
}
}
classA中锁住了ca的引用(this就是ca),再锁住cb的引用。
classB中锁住了cb的引用,再锁住了ca的引用。
由于ca.show(cb)先执行,所以先lock(this),这个可以过,因为ca这时候没人引用,然后再lock(lockobj),它传入的是cb,而此时cb也无人引用,所以可以过。
打印信息,其中延时了1000ms。
注意这个时候cb.show(ca)早已经开始执行了。它的lock(this) 要等到classA的两条信息打印完毕,释放了对cb的引用,进去。但是无法继续进入下一个lock(lockobj), 因为classA的第2 个循环已经进入了lock(this),占用了对ca的引用。
再对比一下执行结果,验证一下勇哥所讲。
引用一些资料:
什么是死锁?
线程死锁是指由于两个或者多个线程互相持有对方所需要的资源会互相等待对方释放资源,导致这些线程处于等待状态,无法前往执行。如果线程都不主动释放所占有的资源,将产生死锁。
当然死锁的产生是必须要满足一些特定条件的:
1.互斥条件:进程对于所分配到的资源具有排它性,即一个资源只能被一个进程占用,直到被该进程释放
2.请求和保持条件:一个进程因请求被占用资源而发生阻塞时,对已获得的资源保持不放。
3.不剥夺条件:任何一个资源在没被该进程释放之前,任何其他进程都无法对他剥夺占用
4.循环等待条件:当发生死锁时,所等待的进程必定会形成一个环路(类似于死循环),造成永久阻塞。
按上面说法,本例子死锁是因为1(互斥条件)
---------------------
作者:hackpig
来源:www.skcircle.com
版权声明:本文为博主原创文章,转载请附上博文链接!

