说我有两个这样的课程:
class A{
private static Random random = new Random();
public A(){
// Do something.
}
public Integer methodGetsCalledQuiteOften(){
return random.nextInt();
}
}
class B{
private Random random;
public A(){
random = new Random();
// Do something.
}
public Integer methodGetsCalledQuiteOften(){
return random.nextInt();
}
}
在两个实例化多次实例化并且这两个类的实例'方法methodGetsCalledQuiteOften
都被大量调用的情况下,是否有真正的优势/劣势(时间,内存)使用一个在类A中保存Random()
的静态变量而不是在每个实例中创建一个新的Random()
对象,就像在B类中一样?
应用程序是多线程的,更高级别的随机性因此我认为我将使用静态SecureRandom
。如果在分析后这将是一个真正的速度因素,我可能会选择别的东西。
答案 0 :(得分:6)
真正的优势/劣势取决于真正的代码。换句话说,它取决于创建B
的频率与调用方法的频率等等。您应该对应用程序进行概要分析,看看它是否有合理的差异。
A会比B更高效吗?当然。但是,你是否会注意到取决于你的用法。 A会比B使用更少的内存吗?当然,但你是否关心取决于你要保留多少个A / B实例。
真正唯一的另一个考虑因素是决定论。由于您没有为Random实例指定种子,我认为您不关心是否可以从Random重现数字序列。但是值得注意的是......如果你有一个共享的随机数,那么为某个A实例保证一定数量的确定性数字序列要比在B中为每个实例保留一个数字更加困难。
答案 1 :(得分:5)
对可变的静态说不,m'kay。
这是一个残暴的设计。通常引用的结果是可测试性失败。没有重新加载课程就很难重现。由于许多其他原因,糟糕的设计也很糟糕。仅举一例,默认情况下,类应与线程无关。添加一个可变的静态,你是线程敌对的 - 一个不好的地方。
每次创建一个新实例似乎都很浪费。当然,虽然不过早优化(如果您正在优化,则不会使用java.util.Random
)。初始看到递增也可能导致问题。
最好的方法是传入一个实例(“Parameterise from Above”或“正确使用构造函数”)。然后你可以测试,复制,模拟等等。你是高效的,可以翻转不同的实现。
答案 2 :(得分:3)
如果您的程序是单线程的,那么您的Random
应该是类成员(static
)。这样效率更高一些。使用SecureRandom
时更为重要,methodGetsCalledQuiteOften()
可能需要相对较长的时间才能播种。
如果多个线程最终会调用Random
,则问题会更复杂一些。该类是线程安全的,但在并发更改期间保护其状态所需的开销可能与创建static
的新的独立实例相当。
我可能会坚持使用{{1}}成员,直到我注意到随机数生成器的线程之间存在很多争用,这可能永远不会发生。
答案 3 :(得分:2)
当预计实例不会发生变化或想要在实例之间共享时,请使用静态变量。
private final static int SOME_CONSTANT=1;
就是一个例子。
public class USA {
private final static Map statesOfTheUnion = new HashMap();
// etc
}
可能是另一个。在后一种情况下,我们不希望状态会在不同实例之间发生变化。因此,每个实例都有自己的副本是没有意义的。
答案 4 :(得分:2)
虽然实例化A类比B类实际上快了(10倍),但这只会影响你每秒100.000次。
关于线程安全性,我的理解是 .nextInt()基于 .next(),它应该是线程安全的。所以多线程不应该在这里给出任何问题。
但更重要的是,两个班级的行为可能会有所不同。 A类实例会为每个实例提供一些随机数字序列,但B类实例可能会给出相同的“随机”数字序列(这种行为在不同平台上可能会有所不同!)。 Javadoc规范声明:
如果创建了两个Random实例 与同一种子,相同 方法调用的序列是为了 每一个,他们都会产生并返回 相同的数字序列。
因此,如果随机性非常重要,您可能需要考虑为Random构造函数提供唯一种子,或者使用较慢的 java.security.SecureRandom 更好地实现Random。
答案 5 :(得分:1)
访问静态资源不是线程安全的。您可能会在线程环境中获得奇怪/不可预测的结果。
答案 6 :(得分:1)
好吧,既然Random
类采取了必要的步骤来确保线程安全,我认为将其设置为静态没有任何问题。
由于其状态包括单个AtomicLong
对象(8个字节),因此不会浪费大量内存(除非您计划创建巨大的数量的B
个实例)。
所以,我会说,两种方式都没什么区别。
答案 7 :(得分:1)
如果您使用java.util.Random
,请注意它是linear congruential generator,其中包含与相关性相关的众所周知的问题。对我来说,真正的问题是应用程序应该从单个系列中选择还是从具有不同种子的几个系列中选择。
答案 8 :(得分:0)
就时间和内存而言,我无法想到任何重大优势(静态变量将成为类定义的一部分而不是堆上的一部分)。但是,当您知道将从多个位置访问对象时,静态变量很有用。 hvgotcodes是正确的,但使用静态资源不是线程安全的。但如果您只读取静态值,那么使用线程就可以了。
它将使您不必将对已启动对象(A或B)的引用传递给其他对象以便使用random
答案 9 :(得分:-1)
静态变量的好处(要点):
可以定义常量而无需占用额外的内存(每个类别一个)。
可以在不实例化类的情况下访问常量。
静态方法的好处:
可以定义与实例无关的行为,而不必担心与类实例的意外交互。