Skip to content

使用 lock(this) 进行同步

🏷️ C# 学习

使用 lock(this) 能够实现线程同步,但是会导致类型缺乏健壮性,容易发生死锁。

下面的示例展示了一个使用 lock(this) 导致死锁的情况。

示例代码

SynchroThis.cs

cs
using System;
using System.Threading;

namespace SynchroThis
{
    /// <summary>
    /// 使用 this 来同步线程
    /// 缺乏健壮性
    /// </summary>
    class SynchroThis
    {
        private int i = 0;

        public void Work(Object state)
        {
            lock(this)
            {
                Console.WriteLine("i 的值为:{0}", i.ToString());
                i++;
                Thread.Sleep(200);
                Console.WriteLine("i 自增 1 后的值为:{0}", i.ToString());
            }
        }
    }
}

Program.cs

cs
using System;
using System.Threading;

namespace SynchroThis
{
    class Program
    {
        static void Main(string args)
        {
            SynchroThis st = new SynchroThis();
            // 恶意的使用者
            Monitor.Enter(st);
            // 正常的使用者
            // 但是受到恶意使用者的影响
            // 这里的完全正确,却被死锁
            Thread t = new Thread(st.Work);
            t.Start();
            t.Join();
            // 程序不会执行到这里
            Console.WriteLine("使用结束");
            Console.Read();
        }
    }
}

技巧

应当完全避免使用 this 对象和当前类型对象(typeof(classname))作为同步对象,而应该在类型中定义私有的同步对象,同时应使用 lock 而不是 Monitor 类型,这样可以有效的减少同步块不被释放的情况。