我正在重新考虑一些代码,并且想知道在实例构造函数中使用lock
。
public class MyClass {
private static Int32 counter = 0;
private Int32 myCount;
public MyClass() {
lock(this) {
counter++;
myCount = counter;
}
}
}
请确认
如果原始程序员的意图是让每个实例知道它的'count',我将如何同步访问'counter'成员以确保另一个线程不是新的MyClass
和在此计数设定之前更改计数?
FYI - 此课程不是单身人士。实例必须只知道它们的编号。
答案 0 :(得分:12)
如果你只是增加一个数字,那就有一个特殊的类(Interlocked)......
http://msdn.microsoft.com/en-us/library/system.threading.interlocked.increment.aspx
Interlocked.Increment Method
增加指定变量并将结果存储为原子操作。
System.Threading.Interlocked.Increment(myField);
有关线程最佳实践的更多信息......
答案 1 :(得分:4)
我猜这是针对单身模式或类似的东西。你想要做的不是锁定你的对象,而是在修改它时锁定计数器。
private static int counter = 0;
private static object counterLock = new Object();
lock(counterLock) {
counter++;
myCounter = counter;
}
因为您当前的代码有点多余。特别是在构造函数中,只有一个线程可以调用构造函数,这与可以跨线程共享并可以从任何共享线程访问的方法不同。
从我可以告诉您的代码中,您试图在创建对象时为对象提供当前计数。因此,使用上面的代码,计数器将在计数器更新并在本地设置时被锁定。所以其他所有构造函数都必须等待计数器被释放。
答案 2 :(得分:3)
您可以使用另一个静态对象来锁定它。
private static Object lockObj = new Object();
并在构造函数中锁定此对象。
lock(lockObj){}
但是,由于.NET
中的编译器优化(例如java
答案 3 :(得分:3)
@ajmastrean
我不是说你应该使用单例模式本身,而是采用封装实例化过程的方法。
即
我遇到了一个问题,如果你怎么知道计数何时下降? ;)
考虑一下,你可以在析构函数中添加代码,调用另一个静态方法来递减计数器:D
答案 4 :(得分:2)
最有效的方法是使用Interlocked增量操作。它将递增计数器并一次性(原子地)返回静态计数器的新设置值
class MyClass {
static int _LastInstanceId = 0;
private readonly int instanceId;
public MyClass() {
this.instanceId = Interlocked.Increment(ref _LastInstanceId);
}
}
在您的原始示例中,lock(this)语句将不具有所需的效果,因为每个单独的实例将具有不同的“this”引用,因此多个实例可能同时更新静态成员。
从某种意义上说,构造函数可以被认为是线程安全的,因为在构造函数完成之前,对构造对象的引用是不可见的,但这对保护静态变量没有任何帮助。
(Mike Schall先把互锁位置)
答案 5 :(得分:0)
我认为如果你修改Singleton Pattern以包含一个计数(显然使用线程安全的方法),你会没事的:)
我意外删除了废话!
我不确定实例构造函数是否线程安全,我记得在设计模式书中读到这个,你需要确保在实例化过程中锁定到位,纯粹是因为这个..
答案 6 :(得分:0)
@ Rob
仅供参考,此类可能不是单身,我需要访问不同的实例。他们必须简单地维持一个计数。你会改变单身模式的哪一部分来执行'计数器'递增?
或者你是否建议我公开一个静态方法来构造阻塞对代码的访问,该代码增加并用锁来读取计数器。
public MyClass {
private static Int32 counter = 0;
public static MyClass GetAnInstance() {
lock(MyClass) {
counter++;
return new MyClass();
}
}
private Int32 myCount;
private MyClass() {
myCount = counter;
}
}