在多线程(或web) c#项目中使用静态属性的风险
本文关键字:静态 属性 项目 多线程 web | 更新日期: 2023-09-27 18:16:01
我对c#中静态属性的多线程访问风险有点困惑。
public class MyClass
{
public static MyClass Static
{
get
{
var c = new MyClass();
c.SomeProperty = "12345";
c.OtherProperty = DateTime.Now.ToString();
return c;
}
}
}
这个示例类提供了一个静态属性,用于创建MyClass的新实例
like a method:
public class MyClass
{
public static MyClass Static()
{
var c = new MyClass();
c.SomeProperty = "12345";
c.OtherProperty = DateTime.Now.ToString();
return c;
}
}
显然,这个属性不是MyClass实例的"存储"框,但它的行为像一个静态方法(如果我阅读好的msdn文章,它是完全线程安全的)。
我的问题是:使用这个概念是否有风险?特别是在web或多线程环境中?
使用它没有特别的实用程序,只是用于简单的读取和清理代码:
MyClass.Static.SomeProperty = "Something";
比
更清楚MyClass.Static().SomeProperty = "Something";
一切帮助将不胜感激
谢谢
在这两个例子中,每次访问属性时都返回一个新的MyClass
实例。当多个线程同时访问静态属性方法时,没有并发性问题的危险,因为它们实际上是在修改它们自己的MyClass
的实例的属性,而不是在它们之间共享。
如果你有这样的东西:
public class MyClass
{
private static MyClass _myClass;
public static MyClass Static
{
get
{
return _myClass ?? (_myClass = new MyClass());
}
}
}
…那么当两个线程试图写/读结果MyClass
实例的属性时,就会出现问题,因为它们操作的是同一个MyClass
引用_myClass
。
即便如此,你发布的代码还是有两个问题:
你需要把它改成一个方法并重命名它,因为它实际上是在创建一些东西,而不是访问任何东西的静态版本。然后可以对返回值进行操作。像这样:
public class MyClass
{
public static MyClass Create()
{
var c = new MyClass();
c.SomeProperty = "12345";
c.OtherProperty = DateTime.Now.ToString();
return c;
}
}
然后像这样使用:
var myClass = MyClass.Create();
myClass.SomeProperty = "Stuff";
当前设置属性的方式意味着它们的值不会被保留,因为下一次访问Static
属性时会创建一个新的MyClass
。
当你设置SomeProperty
时,如果你真的想要更新一个静态实例,你需要锁定一个静态对象来解决多线程问题——就像这样:
public static class MyClass
{
private static readonly object locker = new object();
private static string someProperty;
public void SetSomeProperty(string val)
{
lock (locker)
{
someProperty = val;
}
}
public void GetSomeProperty()
{
lock (locker)
{
return someProperty;
}
}
}
似乎你正在创建一个静态工厂方法,它将给你一个完全实例化的对象。
线程在这里不会是一个问题,因为每次调用这个方法或属性时,你都在创建一个新对象。如果两个线程同时调用同一个方法,它们将各自继续处理它们正在处理的对象
话虽如此,也许你应该重新审视你是如何使用这个类的-因为如果你在代码中调用这个
MyClass.Static.SomeProperty = "Something";
你基本上是在对象被实例化之后扔掉它您需要将它赋值给一个变量并存储它。-下次调用该函数时,你将收到一个新对象。
也许我没有解释清楚,我的问题是关于静态属性的多线程访问。
我可以确认它们是线程安全的,如果返回的对象被绑定到当前线程。
下面是我实现的示例:
public interface IObjectFactory
{
T CreateOrReuse<T>() where T : class, new();
T CreateOrReuse<T>(string key) where T : class, new();
T CreateOrReuse<T>(string key, params object[] args) where T : class;
}
public class ThreadObjectFactory : IObjectFactory
{
// implementation to create and store into the Thread Data
}
public class HttpSessionObjectFactory : IObjectFactory
{
// implementation to create and store into the current session
}
现在是单例:
public class MyClass
{
public int PageLoadCounter = 0;
public static MyClass Static
{
get
{
IObjectFactory factory = new HttpSessionObjectFactory();
return factory.CreateOrReuse<MyClass>();
}
}
}
最后的用法是:
public class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
MyClass.Static.PageLoadCounter++;
}
}
谢谢你的回复,尽管问题不是很清楚