使用私有静态方法使单例线程安全?

发布于 2024-11-27 01:54:38 字数 600 浏览 0 评论 0原文

我有一个类,我想通过创建它的静态实例来将其用作单例。当然我也希望它是线程安全的。

假设我没有共享任何私人数据。但如果我没有记错的话,仍然存在一个问题,即当调用静态对象实例的方法时,方法内的变量在线程之间共享,并且会产生不可预测的结果。

但是,当调用真正的静态方法时,会创建一个新的堆栈帧,因此无论如何它都是线程安全的(对其自身而言)。再说一次,如果我没记错的话。

这种单例模式是线程安全的吗?

class Singleton
{
    public object SomeMethod(object arg) {
        return Singleton.SomeMethodImpl(arg);

    }
    private static object SomeMethodImpl(object arg) {
        // is in unique stack frame?
        object Result;
        ...
        return Result;
    }
}

如果您想知道为什么我不首先创建一个静态类 - 我需要一个基于接口的单例,并且具有不同的实现,作为策略模式的一部分。这不适用于静态类。

I've got a class I want to use as a singleton by creating a static instance of it. Naturally I also want it to be thread safe.

Assume I am not sharing any private data. But if I am not mistaken, there still remains the problem that when calling a method of a static object instance, variables within methods are shared across threads, and would have unpredictable results.

However, when calling a real static method, a new stack frame is created, so it is thread safe (unto itself) anyway. Again, if I am not mistaken.

Would this pattern for a singleton be thread safe?

class Singleton
{
    public object SomeMethod(object arg) {
        return Singleton.SomeMethodImpl(arg);

    }
    private static object SomeMethodImpl(object arg) {
        // is in unique stack frame?
        object Result;
        ...
        return Result;
    }
}

In case you are wondering why I don't just create a static class in the first place - I need to have a singleton that is based on an interface, and has different implementations, as part of a strategy pattern. This doesn't work for static classes.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

泪是无色的血 2024-12-04 01:54:38

只要您的方法没有从实例方法或全局范围变量获取状态,您的方法就是可重入且线程安全的。它不一定必须是静态的。就像这样:

int AddTwo(int a, int b)
{
  return a + b;
}

这是完全线程安全的,并且可以根据需要调用任意次数。即使在方法内部定义变量也可以,只要它们是在方法之间共享的实例变量即可。

方法如:

string ReverseString(string s)
{
    char[] charArray = s.ToCharArray();
    Array.Reverse( charArray );
    return new string( charArray );
}

上面的方法也是可重入且线程安全的。

一旦开始添加变量,无论它们是静态的还是来自不同范围的实例,您就会开始遇到线程安全问题。

class BadExample
{
    private int counter;

    private void IncrementCounter()
    {
        ++counter;
    }
}

在上面的示例中,IncrementCounter() 方法不是线程安全的。

As long as your method isn't getting state from an instance method or global scope variable your method is reentrant and thread safe. It doesn't necessarily have to be static. So something like:

int AddTwo(int a, int b)
{
  return a + b;
}

That's perfectly thread safe and can be called as much as you like. Even defining variables inside of the method is fine as long as they are instance variables that are shared between methods.

A method such as:

string ReverseString(string s)
{
    char[] charArray = s.ToCharArray();
    Array.Reverse( charArray );
    return new string( charArray );
}

The method above is also reentrant and thread safe.

As soon as you start adding variables whether they are static or instance that come from a different scope you start having problems with thread safety.

class BadExample
{
    private int counter;

    private void IncrementCounter()
    {
        ++counter;
    }
}

In the above example the IncrementCounter() method is not thread safe.

﹏半生如梦愿梦如真 2024-12-04 01:54:38

如果我明白你的意思,那么你是对的。

object Result;   // this is on its unique stack frame and is safe so far
Result = new ... // creating something on the heap that Result points to
                 // still safe because it's the only reference to it

即使多个线程调用此方法,它们也会在堆上创建不同的新变量并将它们分配给不同堆栈上的 Result。

你面临的唯一危险是如果你有私人领域。

方法中的变量是临时的,仅对该方法调用可见。稍后或并发方法调用分别重新创建这些变量。

您唯一关心的是静态或实例字段。这些需要同步。

If I understand what you mean, then you're correct.

object Result;   // this is on its unique stack frame and is safe so far
Result = new ... // creating something on the heap that Result points to
                 // still safe because it's the only reference to it

Even if multiple threads call this they will create different new variables on the heap and assign them to Result on different stacks.

The only danger you'd be in is if you had private fields.

Variables within a method are temporary and only visible to that method call. Later or concurrent method calls recreate those variables separately.

Your only concern is static or instance fields. Those would need to be synchronized.

沦落红尘 2024-12-04 01:54:38

由于您指定的原因,上面的代码是线程安全的。我看到的问题是你没有实现单例。

您主要担心的是线程安全吗?如果是这样,线程安全通常适用于线程之间共享的对象实例。这意味着只要您不跨线程共享普通对象或在类级别创建静态数据就应该没问题。

我添加了一个使用带有接口的单例的示例,无论有没有工厂。注意:我没有运行这段代码。

public interface ISomething
{
    void Method();
}

public class Class1 : ISomething
{
    public void Method()
    {
        throw new NotImplementedException();
    }
}

public class Class2 : ISomething
{
    public void Method()
    {
        throw new NotImplementedException();
    }
}

public class Singleton
{
    private static ISomething privateObject;

    public static ISomething Instance()
    {
        lock (privateObject)
        {
            if (privateObject == null)
            {

                privateObject = new Class1();
            }
        }

        return privateObject;
    }
}

public class SingletonUsingFactory
{
    private static ISomething privateObject;

    public static ISomething Instance(int param)
    {
        lock (privateObject)
        {
            if (privateObject == null)
            {
                privateObject = FactoryClass.CreationObject(param);
            }
        }

        return privateObject;
    }
}

public static class FactoryClass
{
    public static ISomething CreationObject(int whatToCreate)
    {
        ISomething createdObject;

        switch (whatToCreate)
        {
            case 0:
                createdObject = new Class1();
                break;
            case 1:
                createdObject = new Class2();
                break;
            default:
                throw new Exception();
        }

        return createdObject;
    }
}

The code you have above is thread safe and for the reasons you've specified. The problem I see is you are not implementing a singleton.

Is your main worry about thread safety? If so, thread safety usually applies to object instance being share between threads. That means as long as you don't share a normal object across threads or create static data at the class level you should be ok.

I am adding an example of using singleton with interfaces, with and without a factory. Note: I didn't run this code.

public interface ISomething
{
    void Method();
}

public class Class1 : ISomething
{
    public void Method()
    {
        throw new NotImplementedException();
    }
}

public class Class2 : ISomething
{
    public void Method()
    {
        throw new NotImplementedException();
    }
}

public class Singleton
{
    private static ISomething privateObject;

    public static ISomething Instance()
    {
        lock (privateObject)
        {
            if (privateObject == null)
            {

                privateObject = new Class1();
            }
        }

        return privateObject;
    }
}

public class SingletonUsingFactory
{
    private static ISomething privateObject;

    public static ISomething Instance(int param)
    {
        lock (privateObject)
        {
            if (privateObject == null)
            {
                privateObject = FactoryClass.CreationObject(param);
            }
        }

        return privateObject;
    }
}

public static class FactoryClass
{
    public static ISomething CreationObject(int whatToCreate)
    {
        ISomething createdObject;

        switch (whatToCreate)
        {
            case 0:
                createdObject = new Class1();
                break;
            case 1:
                createdObject = new Class2();
                break;
            default:
                throw new Exception();
        }

        return createdObject;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文