首页 > 解决方案 > 创建对象线程新实例的静态方法是否安全?

问题描述

从我在其他 SO 帖子上读到的内容来看,我的猜测是 CreateTry1 和 CreateTry2 都不是线程安全的,但即使在阅读了这么多之后,我仍然不能 100% 确定这是正确的。

public ClassA
{
  private string MyString;

  private ClassA(string myString)
  {
    MyString = myString;
  }

  public static CreateTry1(string aString)
  {
    return new ClassA(aString);
  }

  public static CreateTry2(string aString)
  {
    ClassA a = new ClassA();
    a.MyString = aString;
    return a;
}

// The Below is not the main focus of the question
static public void Main(String[] args)
{
  Thread t1 = new Thread(p =>
  {
    int i = 0;
    while(i < 1000000)
    {
      ClassA newA = ClassA.CreateTry2("Hello");
      i++;
    }
  });

  Thread t2 = new Thread(p =>
  {
    int i = 0;
    while(i < 1000000)
    {
      ClassA newA = ClassA.CreateTry2("Hello");
      i++;
    }
  });

  t1.Start();
  t2.Start();
}

更多信息 1:澄清

我编辑了代码

这个问题专门与 Selenium Grid 有关。我想如果我更好地理解什么是线程安全的,什么不是线程安全的(通常),那么我就会知道在重构代码以在 Selenium Grid 中运行(并行)时要避免不安全的代码。但是,我想我跳进了游泳池的深处,并且不完全知道如何在这里游泳,所以对此表示歉意。

我认为部分答案很简单,“非静态类中的非静态变量(字段和属性)始终是线程安全的。非静态或静态类中的静态变量(字段和属性)是一般不安全”。


更多信息 2:相关 SO 帖子

我读了很多帖子。一些陈述澄清了事情,而另一些则使事情变得更加混乱。

这个评论最有道理。然而,声明的一部分说,“当你在不同实例中的数据仍然混淆时,很可能是因为数据并不是真正独立的。” 似乎很难看不到您的一个变量(字段)是静态的,所以想知道线程之间的数据交叉污染是如何在他不知道的情况下发生的。

与以下 MSDN 声明相关的任何对话对我来说都完全没有意义:

此类型的任何公共静态(在 Visual Basic 中为 Shared)成员都是线程安全的。不保证任何实例成员都是线程安全的。

1. 关于以上报价

2.关于以上报价。这是一个很好的问题,但起初答案似乎过于复杂。我最终记得“成员”是指类中的字段、属性和方法(不仅仅是字段)。如此广泛的陈述会使答案变得复杂。

下面的帖子“这种扩展方法线程安全吗”是一个很好的问题,但我不知道哪个答案是正确的。我相信这两种方法都是正确的,但 Avner 的答案是一个非常笼统的答案,而 Ondrej 的答案则专门回答了这个问题。

一些帖子,比如这个,提出了“共享状态”这个词,在阅读了以下内容之后,它似乎只不过是一个类中的一个静态字段(但我很容易弄错)。

标签: c#parallel-processingselenium-grid

解决方案


我不确定您要弄清楚什么,但我想知道两件事可能会有所帮助:

  • CreateTry1并且CreateTry2不要访问共享数据。MyString属性不在实例之间共享。所以这些方法是线程安全的。
  • 构造函数保证是线程安全的。并行的多个实例ClassA不会相互干扰,即是线程安全的。

推荐阅读