静态方法是否安全

57 c# asp.net static

我有一个静态计时器类,任何网页都会调用它来计算每个页面构建的时间.

我的问题是静态类线程安全吗?在我的示例中,并发用户会导致启动和停止时间出现问题吗?例如,不同的线程覆盖我的开始和停止值.

public static class Timer
{
    private static DateTime _startTime;
    private static DateTime _stopTime;    

    /// <summary>
    /// Gets the amount of time taken in milliseconds
    /// </summary>
    /// <returns></returns>
    public static decimal Duration()
    {
        TimeSpan duration =  _stopTime - _startTime;
        return duration.Milliseconds;
    }

    public static void Start()
    {
        _startTime = DateTime.Now;
    }

    public static void Stop()
    {
        _stopTime = DateTime.Now;
    }
}
Run Code Online (Sandbox Code Playgroud)

这个类应该是非静态类吗?

(这个类将从asp.net主页调用.)

Jon*_*eet 66

静态方法本质上不是线程安全的.CLR与实例方法的处理方式没有区别.不同之处在于,通常应该尝试使它们具有线程安全性.(我想不出任何不是线程安全的.NET BCL静态方法.)实例方法通常不是线程安全的,因为典型的模式是创建一个对象并从一个线程重复使用它,如果它必须从多个线程使用,统筹涉及包括确保该对象的安全使用.在很多情况下,在协调代码中比在对象本身中更合适.(通常你想让整个操作序列成为有效的原子 - 这是在对象中无法完成的.)

你的Timer类绝对不是线程安全的:两个线程可以轻松地踩在彼此的数据上,并且没有什么可以阻止线程在计算持续时间时使用"陈旧"数据.

Stopwatch改为使用该类 - 这就是它的用途.不可否认,如果你想使用多个线程中的一个实例,你需要采取正常的步骤来确保安全,但总的来说你会处于更好的位置.诚然,这Stopwatch也远非完美 - 请参阅下面的问题和下面的评论以获取更多详细信息 - 但它至少是该类型的设计目标.(谁知道,它可能会被修复一段时间......)

  • 如果您使用多核或多处理器,Stopwatch类本身就存在问题.秒表使用滴答计数来确定持续时间,并且由于BIOS中的错误,秒表可以在一个核心上启动并在另一个核心上停止,其中两个核心上的滴答计数不同步.我在Vss2Git开源应用程序中发现了这一点,该应用程序使用了秒表,有时试图给出负时间.更多信息请参见http://stackoverflow.com/a/7919483/216440 (4认同)

Bil*_*ill 23

这是一个很好的讨论在这里是更侧重于机制和原因,为什么你的例子是不是线程安全的.

总而言之,首先,您的静态变量将被共享.如果你可以使它们成为局部变量,即使它们是静态方法的本地变量,它们仍然会得到自己的堆栈帧,因此是线程安全的.此外,如果您另外保护静态变量(即,此线程中其他人提到的锁和/或其他多线程编程技术),您还可以使示例静态类是线程安全的.

其次,因为您的示例不接受您修改的外部变量实例或其状态可能由另一个线程执行的外部变量实例,所以您的示例在这方面也是线程安全的.

  • 是.但请记住,它需要是方法的局部变量 - 而不是静态类变量.(我认为有时类变量被称为本地变量,但我可能会误解.)既然你说"只使用局部变量",我也认为这意味着你没有指定传入的引用参数到局部变量. (5认同)

Phi*_*ert 20

你的计时器类绝对不是线程安全的.您应该创建一个普通类,并在每次需要测量时间时实例化它:

Timer timer = new Timer();

timer.Start();
//...
timer.Stop();

decimal duration = timer.Duration();
Run Code Online (Sandbox Code Playgroud)

更好的是,有一个内置的.NET类正是这样做的:

Stopwatch sw = Stopwatch.StartNew();

sw.Stop();

TimeSpan duration = sw.Elapsed;
Run Code Online (Sandbox Code Playgroud)


Tom*_*Tom 5

是的,您是对的,此类的静态成员/访问器将导致它们被不同的用户覆盖。

这就是为什么您有实例和非静态成员的原因。