线程安全的静态类

时间:2015-01-25 11:23:23

标签: c# multithreading static

我想知道以下静态类是否是线程安全的,为什么?

public static class Settings
{
    public static string AStringSetting { get; set; }
    public static int AIntSetting { get; set; }

    public static void Load()
    {
        // load values from database
    }
}

我有一个多线程Windows服务,可以将设置加载到服务的开头。 我想在我的服务中添加某种自动刷新功能。我做了一些测试,运行200多个线程读取和写入公共属性,我无法使进程崩溃......

该类线程是否安全? 为什么呢?

3 个答案:

答案 0 :(得分:0)

仅仅因为你无法使你的程序崩溃并不意味着你的类是线程安全的。检查http://en.wikipedia.org/wiki/Thread_safety。在您的情况下,可能会出现竞争条件,因为您的属性访问权限未同步。

答案 1 :(得分:0)

我不是线程专家,但afaik线程安全不是防止崩溃。它更关注可靠的结果。在您的代码示例中,您的属性AStringSettingAIntSetting从未使用过,因此无法确定是否存在线程问题。请考虑以下代码:

if (AStringSetting.Equals("TEST"))
{
    // AStringSetting may not be "TEST" anymore, although it was until a moment ago. 

    if (AIntSetting < 10)
    {
       // no idea what AIntSetting contains now. It was below 10 just a moment ago, though.
       AIntSetting = AIntSetting + 1;
    }
}

此代码不是线程安全的。例如,另一个线程可以在执行第一行时修改两个属性中的一个。或者更糟糕的是,在第一行执行之后。根据代码的作用,最终可能会出现不一致的结果。您将无法依赖于您刚刚测试AStringSettingAIntSetting的内容这一事实,因为您永远不知道另一个线程是否只是更改它们。

为了使您的类线程安全,您应该实现一个线程锁定机制,让所有方法使用该机制(在您的情况下可能是private static Objectlock命令)来阻止访问来自其他线程的静态属性。您的getter和setter也应该使用该锁定机制来确保不会从不同的线程读取或更改属性。

 private static string mStringSetting;
 public static string AStringSetting { 
     get{
         lock(mThreadLock) { return mStringSetting; }
     } 
     set {
         lock(mThreadLock) { mStringSetting = value; }
     }
 }

 private static int mIntSetting;
 public static int AIntSetting { 
     get{
         lock(mThreadLock) { return mIntSetting; }
     } 
     set {
         lock(mThreadLock) { mIntSetting = value; }
     }
 }
 private static Object mThreadLock = new Object();

 public static void IncreaseIntIfLowerThan10AndStringIsTest()
 {
     lock(mThreadLock)
     {
         if (AStringSetting.Equals("TEST"))
         {
             // AStringSettig is still "TEST", no other thread can change it due to the lock
             if (AIntSetting < 10)
             {
                 AIntSetting = AIntSetting + 1;
             }
         }
     }
 }

如果属性具有某种逻辑连接并且依赖于另一种属性,那么即使这可能还不够。如果是这种情况,您可能必须在一个线程安全的步骤中实现实现业务逻辑的线程安全方法,并至少阻止对类外部属性的写访问。

答案 2 :(得分:-1)

您可能希望在此处查看答案:https://stackoverflow.com/a/435045/896697。 Jon Skeet提出了一个非常有趣的观点,即在某些情况下JIT编译器可以缓存值。而且,由于您的目的是获取该应用程序设置的最新版本(或当前版本),您可能无法实现目标(无论线程安全性如何)。