Java:getInstance()单例模式性能

3
我是一位有用的助手,可以为您翻译文本。以下是需要翻译的内容:

我在寻找使用单例类的最高效方法方面遇到了困难。我有三种方法,也许有人可以解释一下最有效的方法:

1:

public functionA() {
    SingletonClassA.getInstance().callA();
    SingletonClassA.getInstance().callB();
    SingletonClassA.getInstance().callC();
    SingletonClassA.getInstance().callD();
    SingletonClassA.getInstance().callE();
}

2.

public functionA() {
    SingletonClassA tmp = SingletonClassA.getInstance();
    tmp.callA();
    tmp.callB();
    tmp.callC();
    tmp.callD();
    tmp.callE();
}

3.

SingletonClassA tmp = SingletonClassA.getInstance();       
public functionA() {
    tmp.callA();
    tmp.callB();
    tmp.callC();
    tmp.callD();
    tmp.callE();
}

我看到了使用方法1的代码,但是我认为更好的方式应该是方法2(如果其他函数也在使用SingletonClassA,则使用方法3)。

我来自于C开发,但是我对Java及其引用不太了解。我只希望它不会消耗太多的内存,并且执行速度快。


1
你是否对你的使用情况进行了每种方法的测量?说实话,这种微观优化很可能不会产生可观的效果。 - sisyphus
我理解一个有C背景的人会问这样的问题,但你不需要担心这样微小的优化。你现在正在使用Java,无论如何代码都会很慢... :) - Marko Popovic
3个回答

3

在讨论性能时,永远不要认为(或正确地说:假设/相信)。

相反:了解Java即时编译器及其功能。惊喜的是:大多数情况下,JIT会将您的微观优化想法拒之门外。只有在真正遇到问题时才考虑性能问题。然后:学习使用Java分析器来测量发生了什么。

意思是:专注于SOLID设计;编写易读、易维护的代码...这通常会导致“好”的代码;而且比在Java上花费时间更有回报。此外:如果您的代码易于维护,则更容易进行更改以修复某些性能问题。

(是的,应该避免犯愚蠢的错误;但是第一个和最大的错误是假设这样做与那样做对性能有好坏影响)。

附注:考虑不使用单例类,而是使用具有单个实例的枚举类。


1
使用只有一个实例的枚举。
如果您在并发环境中关心单例并且希望进行延迟初始化,请使用按需初始化模式

0

如果你想编写最高效的版本,第三种方法非常接近,但是你应该使用一个私有的 final 静态变量,以避免不必要的额外查找:

private static final SingletonClassA singletonA = SingletonClassA.getInstance();       
public functionA() {
    singletonA.callA();
    singletonA.callB();
    singletonA.callC();
    singletonA.callD();
    singletonA.callE();
}

我假设你的单例模式创建方式不会在后面改变,所以使用static也是一个很好的选择。静态变量将为每个类的实例节省4/8字节的内存(32/64位VM),因为该变量将不再是可能许多类实例的一部分,它只会存在一次。

final提示编译器这个变量在初始声明后不会改变,所以不需要进行任何更改检查。请注意,这只是一个提示,可以使编译器更容易地做出决策。在大多数情况下,编译器可以自行确定这一点。然而,向代码读者提示只读变量也是一个好习惯,而final正是这样做的。

private确保变量不是可继承类部分的一部分,因此可以跳过对类层次结构的检查。然而,这更多是编译时性能的提升,因为JVM总是可以准确地确定必须使用类层次结构的哪个版本。

还要注意,类变量应始终具有清晰的名称,指示其目的。 tmp既不清晰,也没有描述其目的。

然而:未经优化的代码性能提升最多只有几个纳秒,如果该函数是所谓的“热”函数(即频繁调用),那么它将被优化得比您使用标准Java代码能做到的更好。因此,在这种特定情况下重写代码的性能提升完全可以忽略不计。

除非您有特定的理由认为您的代码会影响性能,否则编写易于阅读和维护的代码总是比在这种微小级别上进行优化更好。JVM更擅长为您执行此操作,因为它了解有关正在执行的机器的更多详细信息。您在Intel机器上进行的优化可能会导致在ARM系统上执行代码变慢。

优化应始终从架构(全局)级别开始,仅当您测量并证明某些代码部分仍然过慢时,才应开始考虑这种微观级别的优化。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接