【问题标题】:Why are static methods in .Net framework classes always thread-safe?为什么 .Net 框架类中的静态方法总是线程安全的?
【发布时间】:2014-09-01 16:12:01
【问题描述】:

我在 .Net 框架文档的大部分地方都注意到了以下声明。

问题:这其中的秘诀是什么?我不认为静态类总是线程安全的。我的问题与 .Net 框架中可用的标准类有关,而不是开发人员创建的自定义类。

下面的静态类中的“GetString”方法是否会因为该方法是静态方法而成为线程安全的?

public static class MyClass
{
    static int x = 0;

    static MyClass()
    {
        x = 23;
    }

    public static string GetString()
    {
        x++;
        return x.ToString();
    }
}

【问题讨论】:

  • 它们不是线程安全的。
  • 代码默认不是线程安全的 - 静态或其他,声明指出这些成员在设计时考虑了线程安全。
  • 那么为什么我在 .Net 文档中看到的所有 .Net 框架类中总是出现线程安全说明静态方法是线程安全的。我不是指开发人员创建的自定义类,而是框架附带的类。
  • 因为你见过的都是线程安全的。

标签: c# .net thread-safety static-methods


【解决方案1】:

您提到的框架方法并不是线程安全的,因为它们是静态的,而是因为它们被专门设计为线程安全的。线程安全通常很难实现,但对于静态方法通常是必需的,因为它们改变的任何状态都是在线程之间共享的。

您发布的示例方法不是线程安全的,因为它改变了线程之间共享的状态,没有任何同步机制。

【讨论】:

  • 你知道为什么他们让所有的静态方法都是线程安全的吗?这不可能是随机巧合,但似乎背后有某种模式/原因。
  • 好的。我现在明白了。谢谢。
  • @ThomasLevesque 您的第二段不一定正确,原因有两个。首先,它没有考虑无等待算法。其次,GetString() 的语义可以很容易地写成“返回一个介于int.MinValueint.MaxValue 之间的整数的字符串表示形式”,这在当前形式下肯定是线程安全的。 如果方法的语义没有定义,那么你无法确定它是否是“线程安全的”。(顺便说一句,这里的粗体主要是给 OP 的,不是给你的。)
【解决方案2】:

在没有任何线程问题的情况下使用非线程安全实例方法的最简单方法是让该实例仅对一个线程可见(只是不要将对其的引用放在静态或其他任何其他线程中创建它将访问它)。事实上,这种情况在 90% 以上的情况下都会发生,而无需任何特别的努力。

第二个最简单的方法是将锁对象与实例相关联(无论是通过将其用作锁对象,还是在同一范围内为它和锁对象提供一个字段)并确保所有访问锁正确。

对于静态方法,我们没有这些选项,因为没有这样的实例,任何线程都可能调用它或另一个随时发生冲突的静态方法。它甚至可能不是来自同一作者的代码。我们也不能保证其他代码使用我们为它准备的锁定对象。

因此,非线程安全的静态方法的用途非常有限;几乎只适用于在非常有限的情况下使用的私有静态方法,这些限制提供了一次只能由一个线程调用的保证。

因此,对于所有公共静态方法,应确保它们是线程安全的(或者非常清楚地记录它们不是线程安全的,以及这样做的理由)。

事实上,您会发现很多被记录为“非线程安全”的实例方法实际上是。它们被列为“非线程安全”的原因是:

  1. 如果作者没有竭尽全力确认他们的线程安全,他们最好不要声称他们不能 100% 确定。
  2. 在这个方向上犯错是安全的;更糟糕的是,有人添加了自己的同步来添加他们不需要的线程安全,这实际上不会破坏任何东西。
  3. 由于他们没有将该方法记录为线程安全的,因此他们可以在以后的版本中随意更改为非线程安全的方法。

【讨论】:

  • 很好的解释。谢谢。但无法理解:“使用没有任何线程问题的非线程安全实例方法就是让该实例仅对一个线程可见”。
  • 您的意思是实例是在使用它的线程上创建的?
  • 是的。我再补充一点。
【解决方案3】:

您所指的具体示例被设计为线程安全的。也就是说,它们允许并发访问而不会出现死锁或竞争条件。

并非所有类的所有实例都是如此,因为 Microsoft 已选择明确说明哪些方法是线程安全的,哪些方法是为了避免歧义。

见最后一段 - .NET Class Library

.NET Framework 中的所有公共静态成员(方法、属性、字段和事件)都支持多线程环境中的并发访问。因此,可以从两个线程同时调用任何 .NET Framework 静态成员,而不会遇到竞争条件、死锁或崩溃。

对于 .NET Framework 中的所有类和结构,请检查 API 参考文档中的线程安全部分以确定它是否是线程安全的。如果您想在多线程环境中使用非线程安全的类,则必须使用提供必要同步构造的代码包装该类的实例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-17
    • 2016-07-16
    相关资源
    最近更新 更多