5

我正在重构一些代码,并且想知道lock在实例构造函数中使用 a 。

public class MyClass {

    private static Int32 counter = 0;
    private Int32 myCount;

    public MyClass() {

        lock(this) {
            counter++;
            myCount = counter;
        }
    }
}

请确认

  1. 实例构造函数是线程安全的。
  2. lock 语句阻止访问该代码块,而不是静态“计数器”成员。

如果原始程序员的意图是让每个实例都知道它的“计数”,我将如何同步对“计数器”成员的访问,以确保另一个线程不是新线程MyClass并在该线程设置它之前更改计数数数?

仅供参考 - 这个类不是单例。实例必须简单地知道它们的数量。

4

7 回答 7

12

如果你只是增加一个数字,那么有一个特殊的类(互锁)就是这样......

http://msdn.microsoft.com/en-us/library/system.threading.interlocked.increment.aspx

互锁增量法

递增指定变量并将结果存储为原子操作。

System.Threading.Interlocked.Increment(myField);

有关线程最佳实践的更多信息...

http://msdn.microsoft.com/en-us/library/1c9txz50.aspx

于 2008-09-03T14:53:53.790 回答
4

我猜这是一个单例模式或类似的东西。您要做的不是锁定对象,而是在修改计数器时锁定计数器。

private static int counter = 0;
private static object counterLock = new Object();

lock(counterLock) {
    counter++;
    myCounter = counter;
}

因为您当前的代码有点多余。特别是在构造函数中,只有一个线程可以调用构造函数,这与可以跨线程共享并从任何共享线程访问的方法不同。

从我可以从您的代码中得知的一点点,您正试图在创建对象时为其提供当前计数。因此,使用上面的代码,计数器将在本地更新和设置时被锁定。所以所有其他构造函数都必须等待计数器被释放。

于 2008-09-03T14:33:15.353 回答
3

您可以使用另一个静态对象来锁定它。

private static Object lockObj = new Object();

并将此对象锁定在构造函数中。

lock(lockObj){}

但是,我不确定是否存在由于编译器优化而应处理.NET的情况,例如 java

于 2008-09-03T14:34:15.460 回答
3

@ajmastrean

我并不是说你应该使用单例模式本身,而是采用它封装实例化过程的方法。

IE

  • 将构造函数设为私有。
  • 创建一个返回类型的静态实例方法。
  • 在静态实例方法中,在实例化之前使用 lock 关键字。
  • 实例化该类型的新实例。
  • 增加计数。
  • 解锁并返回新实例。

编辑

我遇到了一个问题,如果您怎么知道计数何时下降?;)

再次编辑

考虑一下,您可以将代码添加到调用另一个静态方法以递减计数器的析构函数中:D

于 2008-09-03T14:41:55.380 回答
2

最有效的方法是使用互锁增量操作。它将递增计数器并立即(原子地)返回静态计数器的新设置值

class MyClass {

    static int _LastInstanceId = 0;
    private readonly int instanceId; 

    public MyClass() { 
        this.instanceId = Interlocked.Increment(ref _LastInstanceId);  
    }
}

在您的原始示例中, lock(this) 语句不会产生预期的效果,因为每个单独的实例都会有不同的“this”引用,因此多个实例可能会同时更新静态成员。

从某种意义上说,构造函数可以被认为是线程安全的,因为在构造函数完成之前对正在构造的对象的引用是不可见的,但这对于保护静态变量没有任何好处。

(迈克·沙尔先有互锁位)

于 2008-09-03T15:42:48.040 回答
0

我想如果你修改单例模式以包含一个计数(显然使用线程安全方法),你会没事的:)

编辑

废话不小心删了!

我不确定实例构造函数是否线程安全的,我记得在设计模式书中读到过这个,你需要确保在实例化过程中锁到位,纯粹是因为这个。

于 2008-09-03T14:35:45.050 回答
0

@

仅供参考,此类可能不是单例,我需要访问不同的实例。他们必须简单地保持计数。您将更改单例模式的哪一部分来执行“计数器”递增?

或者你是否建议我公开一个静态方法来构造阻塞访问代码,该代码递增并使用锁读取计数器。

public MyClass {

    private static Int32 counter = 0;
    public static MyClass GetAnInstance() {

        lock(MyClass) {
            counter++;
            return new MyClass();
        }
    }

    private Int32 myCount;
    private MyClass() {
        myCount = counter;
    }
}
于 2008-09-03T14:37:43.750 回答