zoukankan      html  css  js  c++  java
  • 改善C#程序的建议8:避免锁定不恰当的同步对象

    在C#中让线程同步的另一种编码方式就是使用线程锁。所谓线程锁,就是锁住一个资源,使得应用程序只能在此刻有一个线程访问该资源。可以用下面这句不是那么贴切的话来理解线程锁的作用:锁,就是让多线程变成单线程。在C#中,可以将被锁定的资源理解成new出来的普通对象。

    既然需要锁定的资源就是一个C#中的对象,我们就该仔细思考,到底什么样的对象能够成为一个锁对象(也叫同步对象)?在选择同步对象的时候,应当始终注意以下几点:

        q同步对象在需要同步的多个线程中是可见的、同一个对象;

        q非静态方法中,静态变量不应作为同步对象;

        q值类型对象不能作为同步对象;

        q避免将字符串作为同步对象。

        q降低同步对象的可见性。

     

    第一点,需要锁定的对象在多个线程中是可见的、同一个对象

    “可见的”这是显而易见的,如果对象不可见,就不能被锁定。“同一个对象”,这理解起来也很好理解,如果锁定的不是同一个对象,那又如何来同步两个对象呢?可是,不见得我们在这上面不会犯错误。为了阐述本建议,我们先模拟一个必须使用到锁的场景:在遍历一个集合的过程中,同时在另外一个线程中删除集合中的某项。下面的这个例子中,如果没有lock语句,将会抛出异常InvalidOperationException:“集合已修改;可能无法执行枚举”:

    publicpartialclass FormMain : Form
    {
    public FormMain()
    {
    InitializeComponent();
    }

    AutoResetEvent autoSet
    =new AutoResetEvent(false);
    List
    <string> tempList =new List<string>() { "init0", "init1", "init2" };

    privatevoid buttonStartThreads_Click(object sender, EventArgs e)
    {
    object syncObj =newobject();

    Thread t1
    =new Thread(() =>
    {
    //确保等待t2开始之后才运行下面的代码
    autoSet.WaitOne();
    lock (syncObj)
    {
    foreach (var item in tempList)
    {
    Thread.Sleep(
    1000);
    }
    }
    });
    t1.IsBackground
    =true;
    t1.Start();

    Thread t2
    =new Thread(() =>
    {
    //通知t1可以执行代码
    autoSet.Set();
    //沉睡1秒是为了确保删除操作在t1的迭代过程中
    Thread.Sleep(1000);
    lock (syncObj)
    {
    tempList.RemoveAt(
    1);
    }
    });
    t2.IsBackground
    =true;
    t2.Start();
    }
    }

    这是一个Winform窗体应用程序,我们需要演示的功能在按钮的点击事件中。对象syncObj对于线程t1和t2来说,在CLR中肯定是同一个对象。所以上面的示例运行没有问题。

    现在,我们将以上示例重构一下。将实际的工作代码移到一个类型SampleClass中去,该示例要在多个SampleClass实例间操作一个静态字段:

    privatevoid buttonStartThreads_Click(object sender, EventArgs e)
    {
    SampleClass sample1
    =new SampleClass();
    SampleClass sample2
    =new SampleClass();
    sample1.StartT1();
    sample2.StartT2();
    }

    class SampleClass
    {
    publicstatic List<string> TempList
  • 相关阅读:
    记录centos中pptpd server 的配置
    记录IIS7.5的rewrite配置
    duration异常导致的移动端音频无法播放问题
    移动端web开发的几个tips记录
    关于ie8中微软雅黑字体显示的问题
    移动端audio使用的一个注意事项
    关于window.opener的一个小记录
    【翻译】行高的相关计算
    spring 事务管理(编程式)
    CSDN上看到的一篇有关Spring JDBC事务管理的文章(内容比较全)
  • 原文地址:https://www.cnblogs.com/xyqCreator/p/2626443.html
Copyright © 2011-2022 走看看