【问题标题】:Non static members in Singleton classSingleton 类中的非静态成员
【发布时间】:2014-05-11 02:17:04
【问题描述】:

我正在做一个如下的单例课程。

public class SingletonTest {

    private static SingletonTest instance;

    private Integer result;

    private SingletonTest() {   
    }

    public synchronized static SingletonTest getInstance(){
        if(instance == null){
            instance = new SingletonTest();
        }
        return instance;
    }

    public Integer calculateResult(int value1, int value2) {
        result = value1 + value2;
        return result;
    }
}

但是当我从多个线程(使用 JMeter)调用非静态成员时会出现问题。

举例:

线程 1: SingletonTest.getInstance().calculateResult(1,2) -> 返回 3

线程 2: SingletonTest.getInstance().calculateResult(3,2) -> 返回 3

我认为这是因为 2 个线程同时访问方法并覆盖了名为 result 的 de 属性。

【问题讨论】:

  • 嗯,是的 - 你有一个竞争条件。这与它是单例无关,与不安全地改变共享状态有关。您需要同步,或使用AtomicInteger 之类的东西。这里真正的问题是什么?
  • 是的,这就是“单例”的工作方式。你有一个共享状态的实例。
  • 这很有可能 - 您必须应用锁定机制来防止竞争条件。
  • 甚至不需要实例变量。 calculateResult 方法可以返回一个局部变量。那么就不需要同步了。
  • @fge - 初始化是线程安全的,因为 getInstance 是同步的。

标签: java multithreading methods static singleton


【解决方案1】:

你是对的,第二个线程正在访问第一个线程的结果集的值。

如果你正在修改一个对多个线程可见的值,你应该同步操作。

public synchronized Integer calculateResult(int value1, int value2) {
    result = value1 + value2;
    return result;
}

这样,第一个调用方法的线程获得了单例的锁,而第二个线程在完成之前不能访问它。

如果您打算使用并发,您可能应该查看official tutorials,尤其是this

【讨论】:

  • 我读过,同步在性能方面非常昂贵(同步方法的运行速度可能比非同步方法慢 100 倍)。如何进行性能提升?
  • @Hector 尝试使用AtomicInteger
  • 实例变量和返回类型只是简化问题的一个例子。我的项目中返回的对象实际上是一个 HashMap。
  • 谢谢罗伯托,我不知道那门课。
【解决方案2】:

您的猜测是正确的并且它正在发生,因为您的共享结果实例变量不是线程安全的。 不知道你为什么要分享它。修复代码在这里:

public class SingletonTest {

    private static SingletonTest instance;

    private SingletonTest() {   
    }

    public synchronized static SingletonTest getInstance(){
        if(instance == null){
            instance = new SingletonTest();
        }
        return instance;
    }

    public Integer calculateResult(int value1, int value2) {
        Integer result = value1 + value2;
        return result;
    }
}

【讨论】:

  • 实例变量和返回类型只是简化问题的一个例子。我的项目中返回的对象实际上是一个 HashMap。
  • 好吧,但如果您将真实的数据结构放入您的问题中会有所帮助,因为根据操作的不同数据结构,使它们成为线程安全的可能会有所不同。如果您使用 ConcurrentHashMap 及其 CAS 操作 (putifabsent),您可以获得预期的结果,而不是使用 HashMap。如果您让我知道您使用什么作为密钥,我可以修改我的代码。希望对您有所帮助。
【解决方案3】:

试试这个

public class Singleton {

    private static Singleton instance = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {
         return instance;
    }
}

【讨论】:

  • 你需要在 C# 中用谷歌实现单例,而你的答案无论如何都没有解决 OPs 问题。
猜你喜欢
  • 1970-01-01
  • 2012-04-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-20
  • 2014-11-04
相关资源
最近更新 更多