简体   繁体   English

静态关键字,状态/实例变量和线程安全性

[英]Static keyword, state/instance variables, and thread safety

First of all, the static keyword. 首先,static关键字。

I've read several articles and past threads on here covering the static keyword. 我在这里阅读了几篇关于static关键字的文章和过去的帖子。 I haven't found many scenarios listed of when I should use it. 我没有找到许多我应该使用它的场景。 All I know is it doesn't create an object on the heap which tells me it would be good from a performance point of view for an object used a lot. 我所知道的是它不会在堆上创建一个对象,它告诉我从性能的角度来看,对于一个经常使用的对象来说会很好。

Is there any other reason to use it? 有没有其他理由使用它?

Also, I have read something about the static keyword and how it shouldn't be used with instance variables or to alter state. 另外,我已经阅读了一些关于static关键字的内容,以及它不应该如何与实例变量一起使用或改变状态。 Can someone clarify this? 有人可以澄清一下吗? It seems like this is a case of 2+2 but I can't get an answer (missing a few fundamental and simple pieces of knowledge). 这似乎是2 + 2的情况,但我无法得到答案(缺少一些基本和简单的知识)。

Lastly, on the topic of thread safety, what should I look for in my code to get an idea of thread safety? 最后,关于线程安全的主题,我应该在代码中查找什么来了解线程安全性?

I have posted this in VB.NET too because I don't think different languages (C#/VB.NET) will have different rules. 我也在VB.NET中发布了这个,因为我不认为不同的语言(C#/ VB.NET)会有不同的规则。

Thanks 谢谢

The static keyword means something different in C, but in C# and Java it declares methods and variables to be of the class rather than an object. static关键字在C中意味着不同的东西,但在C#和Java中,它声明方法和变量属于类而不是对象。

You would want to use it for methods and variables that don't need any data from a particular object, but use the same data for each object of that type. 您可能希望将它用于不需要来自特定对象的任何数据的方法和变量,但对该类型的每个对象使用相同的数据。

For example String.Format() is a static method of the String class. 例如,String.Format()是String类的静态方法。 You call it in your code without creating a String instance. 您可以在代码中调用它而无需创建String实例。 Likewise, Math.Pi would be a class variable. 同样,Math.Pi将是一个类变量。

But something like a length method doesn't make any sense unless it acts upon a specific instance of a string, so it would have to be an instance method. 但是像长度方法这样的东西没有任何意义,除非它作用于字符串的特定实例,因此它必须是一个实例方法。 Eg, x = "hello".Length(); 例如,x =“hello”.Length();

So if you want your method to be called with just the class name and not on an object, then you make a static method. 因此,如果您希望仅使用类名称而不是对象来调用方法,则可以创建静态方法。 Note that such a method can only reference static variables and call static methods, as it doesn't have an object with which to reference non-static members. 请注意,此类方法只能引用静态变量并调用静态方法,因为它没有用于引用非静态成员的对象。

In C, the static keyword denotes file scope linkage. 在C中,static关键字表示文件范围链接。 A top-level static variable or function does not get its name exported to other compiled object code. 顶级静态变量或函数的名称不会导出到其他编译对象代码。 So two files can declare static variables of the same name and not create a conflict. 因此,两个文件可以声明相同名称的静态变量,而不会产生冲突。 We don't have this problem in C#, because there are namespaces, and private, protected, and public keywords to denote visibility. 我们在C#中没有这个问题,因为有名称空间,私有,受保护和公共关键字来表示可见性。

Yet another meaning is for static variables within a function in C. These variables retain their value between calls to the function. 另一个含义是C中函数内的静态变量。这些变量在函数调用之间保留它们的值。 For example, you could use one to count the number of times the function has been called. 例如,您可以使用一个来计算调用函数的次数。 Static variables in C# also have this property, but you don't declare them within the method as in C, just within the class. C#中的静态变量也具有此属性,但是您不在C中的方法中声明它们,只是在类中。

Lastly, on the topic of thread safety, what should I look for in my code to get an idea of thread safety? 最后,关于线程安全的主题,我应该在代码中查找什么来了解线程安全性?

Writing thread-safe code is a hefty topic that I won't go into here, but I will say one thing on the topic of static & thread safety. 编写线程安全的代码是一个非常重要的主题,我不会在这里讨论,但我会就静态和线程安全这一主题说一件事。

Most methods of ensuring code runs as intended for multiple calling threads involve some kind of locking on an object instance. 确保代码按预期运行多个调用线程的大多数方法都涉及对对象实例的某种锁定。 You will notice that in the .NET framework (BCL), all static members are threadsafe. 您会注意到在.NET框架(BCL)中,所有静态成员都是线程安全的。 This is because there is no clear way of knowing what instance of an object ought to be locked on in order to share this resource between all conceivable callers. 这是因为没有明确的方法可以知道对象的哪个实例应该被锁定以便在所有可想到的调用者之间共享该资源。

Old guidelines used to suggest locking on the type itself, ie: 旧指南用于建议锁定类型本身,即:

lock (typeof(SomeType))
{
    SomeType.SomeStaticMethod(...);
}

This approach is now discouraged and is inadvisable because there is no way of controlling the order of accesses to these lock objects across all conceivable calling threads. 现在不鼓励这种方法并且是不可取的,因为无法控制跨所有可想到的调用线程访问这些锁定对象的顺序。 Locking on public objects (including ICollection.SyncRoot , which is now deprecated for the same reason) is opening the door to deadlocks. 锁定公共对象(包括ICollection.SyncRoot ,现在因同样的原因而被弃用)正在打开死锁的大门。 In the case above, the type instance is publically available, and should not be locked upon. 在上面的例子中,类型实例是公共可用的,不应该被锁定。

Given that there is no single instance that all clients of static methods can reasonably agree upon using for their access of static members, Microsoft's BCL team has had to make all static members typesafe. 鉴于没有单个实例静态方法的所有客户端可以合理地同意使用静态成员,Microsoft的BCL团队必须使所有静态成员都安全。 Thankfully for them, static members are few and far between. 值得庆幸的是,静态成员很少。

If you want to store something which is unique per instance, it should be an instance variable. 如果要存储每个实例唯一的东西,它应该是一个实例变量。 You can make other data as static, if you think it is not unique per instance (or does not require creating an instance). 如果您认为其他数据不是每个实例唯一(或者不需要创建实例),则可以将其他数据设置为静态数据。

eg String.Empty (which is a public static readonly variable). 例如String.Empty(这是一个公共静态只读变量)。 Using this doesn't require you to create a new instance of string. 使用此功能不需要您创建新的字符串实例。

I use static variables to hold values (like sql querys) that are read from files, in functions that are going to be called alot (like in a loop). 我使用静态变量来保存从文件读取的值(如sql查询),在将要调用的函数中(如在循环中)。 Avoids hitting the disk every time the function is called and is a good use of "information hiding". 每次调用函数时都避免碰到磁盘,并且很好地利用了“信息隐藏”。

I think this answers my questions quite well (covers usage): 我认为这很好地回答了我的问题(涵盖用法):

http://msdn.microsoft.com/en-us/library/79b3xss3.aspx http://msdn.microsoft.com/en-us/library/79b3xss3.aspx

Actually static variables are NOT on the stack, they're kept in a special segment of memory that's neither the stack nor the heap. 实际上静态变量不在堆栈中,它们保存在一个特殊的内存段中,既不是堆栈也不是堆。 Also, whether a variable is on the heap or the stack will have no affect on performance whatsoever. 此外,变量是在堆上还是堆栈上对性能没有任何影响。

Static function variables are variables that exist in a function and if changed retain their value between calls. 静态函数变量是函数中存在的变量,如果更改,则在调用之间保留其值。 They can be thought of as global values that are initialized on demand and can only be used in the function where they're declared. 它们可以被视为按需初始化的全局值,只能在声明它们的函数中使用。 IMO there's really no good reason to use static variables in a function, other than for the occasional bit of testing. IMO没有充分的理由在函数中使用静态变量,除了偶尔的测试。

Static member variables are variables shared between all instances of a class. 静态成员变量是类的所有实例之间共享的变量。 So if your "Person" has a static member named "mCountry" then all people will share that variable. 因此,如果您的“Person”有一个名为“mCountry”的静态成员,那么所有人都将共享该变量。 If one person changes it, it changes for everyone. 如果一个人改变它,它会改变每个人。 Static members are useful as it allows all instances of a class to share the same data, thus saving memory. 静态成员很有用,因为它允许类的所有实例共享相同的数据,从而节省内存。

Here's a pretty common use case for static class variables: 这是静态类变量的一个非常常见的用例:

public class Foo
{
   private static Dictionary<string, Foo> Foos = 
      new Dictionary<string, Foo>();

   public static Foo Create(string key)
   {
      if (Foos.ContainsKey(key)) return Foos[key];
      Foos.Add(key, new Foo(key));
   }

   public string Key { get; set; }

   private Foo(string key)
   {
      Key = key;
   }
}

Hiding the constructor and the collection allows the class itself to broker all Foo objects created by the application. 隐藏构造函数和集合允许类本身代理应用程序创建的所有Foo对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM