在 Java 中传递参数或使用静态变量的速度更快?
What is faster passing arguments or using static variable in Java?
我必须使用一个永远不会在方法中更改的变量,该方法将在许多线程中频繁使用。这些变体中哪个更有效?
变体 1:
public class Test {
private static int myVar;
public Test(int myVar){
this.myVar=myVar;
}
public void frequentlyUsedMultiThreadMethod(){
//read myVar
}
}
变体 2:
public class Test {
public void frequentlyUsedMultiThreadMethod(int myVar){
//read myVar
}
}
变体 3:
public class Test {
private final int myVar;
public Test(int myVar){
this.myVar=myVar;
}
public void frequentlyUsedMultiThreadMethod(){
//read myVar
}
}
变体 2 可能稍微好一些,因为可以从那里的堆栈中提取内容。
但是:您应该更加担心创建一个好(又名SOLID
) 设计,而不是担心这些微妙之处。
非常 很难理解 JVM 和即时编译器首先会对您的输入执行什么操作。
意思是:你专注于创造好的设计;你避免了彻头彻尾的愚蠢错误; 好 "performance thinking" 就足够了。其他都是过早的优化。
换句话说:只有性能问题……如果您注意到它们。然后,您不会猜到什么更好;您开始分析您的特定应用程序,以了解真正瓶颈在运行时的位置。
当然,你的问题很有趣"what happens at runtime";但它确实 "not relevant" 指导您的 design/implementation 决定。这些需要由创建有用的抽象的意愿和真正适合您的领域的 "model" 驱动。因为这些才是真正重要的事情!
然后你最终得到其他人可以理解的代码;更重要的是:当你弄清楚你的真正问题是什么时,这可以在以后改变!
无论从哪个位置读取单个 int
都非常快,以至于您很难构建一段代码来证明三种方法之间有意义的时间差异你的问题,更不用说在任意代码中找到差异了。构建基准的问题是变量永远不会改变,因此编译器将被允许在每次方法调用时读取一次,即使 frequentlyUsedMultiThreadMethod
在循环中访问它也是如此。
在这种情况下,最好的方法是考虑哪种方法能反映程序中数据的逻辑使用。
- 应该放弃第一种方法,因为多个实例设置相同的静态变量。当使用相同的值时,这是令人困惑的,而当
myVar
的多个值用于不同的实例时,这是错误的。
- 第二种方法要求调用者多次传递同一个变量,而该值在构造时可用。虽然比第一种方法更容易混淆,但这种方法并不理想。
- 第三种方法在代码中显示
myVar
的值是每个实例一个,并且不会更改。对于您在问题中描述的情况,这是最合乎逻辑的方法。
最简单、最清晰和最不容易出错的解决方案也是最快(或足够快)的,这在 Java 中很常见。
在担心速度之前,你应该问问自己;什么是最简单、最清晰和最不容易出错的方法?通过静态值传递值非常容易出错,尤其是当您拥有多线程应用程序时。不要这样做。如果您的程序无法运行,那么速度并不重要。
但是,在这种情况下,使用 static
字段也会造成混淆。调用者不清楚他们必须首先设置什么。如果你使用递归,这将使你的工作更加困难。
更糟糕的是,局部变量比静态字段更能优化。这意味着静态字段也更慢,可能更慢。
注意:为了防止 JIT 优化,JMH 使用 "blackhole" 作为结果值来阻止代码被优化掉,它使用 static
字段来做到这一点。
选项 3 可能是最好的,前提是值永远不会改变,尤其是如果您有多个值,但是如果值确实改变,它会变慢,因为您每次都会增加创建 Test
对象的开销, JIT 可能无法优化。
这个解决方案怎么样,使用更少的内存,没有创建实例。你需要一些方法。数据将存储在线程堆栈中,并减少线程上下文切换,如果您重用 ThreadPoolExecutor 等线程,则会消耗额外的时间。
如果可以为其他用例更改 myVar,最好将其作为参数添加到方法中。
public class Test {
public static void frequentlyUsedMultiThreadMethod(int myVar){
//read myVar
}
}
我必须使用一个永远不会在方法中更改的变量,该方法将在许多线程中频繁使用。这些变体中哪个更有效?
变体 1:
public class Test {
private static int myVar;
public Test(int myVar){
this.myVar=myVar;
}
public void frequentlyUsedMultiThreadMethod(){
//read myVar
}
}
变体 2:
public class Test {
public void frequentlyUsedMultiThreadMethod(int myVar){
//read myVar
}
}
变体 3:
public class Test {
private final int myVar;
public Test(int myVar){
this.myVar=myVar;
}
public void frequentlyUsedMultiThreadMethod(){
//read myVar
}
}
变体 2 可能稍微好一些,因为可以从那里的堆栈中提取内容。
但是:您应该更加担心创建一个好(又名SOLID ) 设计,而不是担心这些微妙之处。
非常 很难理解 JVM 和即时编译器首先会对您的输入执行什么操作。
意思是:你专注于创造好的设计;你避免了彻头彻尾的愚蠢错误; 好 "performance thinking" 就足够了。其他都是过早的优化。
换句话说:只有性能问题……如果您注意到它们。然后,您不会猜到什么更好;您开始分析您的特定应用程序,以了解真正瓶颈在运行时的位置。
当然,你的问题很有趣"what happens at runtime";但它确实 "not relevant" 指导您的 design/implementation 决定。这些需要由创建有用的抽象的意愿和真正适合您的领域的 "model" 驱动。因为这些才是真正重要的事情!
然后你最终得到其他人可以理解的代码;更重要的是:当你弄清楚你的真正问题是什么时,这可以在以后改变!
无论从哪个位置读取单个 int
都非常快,以至于您很难构建一段代码来证明三种方法之间有意义的时间差异你的问题,更不用说在任意代码中找到差异了。构建基准的问题是变量永远不会改变,因此编译器将被允许在每次方法调用时读取一次,即使 frequentlyUsedMultiThreadMethod
在循环中访问它也是如此。
在这种情况下,最好的方法是考虑哪种方法能反映程序中数据的逻辑使用。
- 应该放弃第一种方法,因为多个实例设置相同的静态变量。当使用相同的值时,这是令人困惑的,而当
myVar
的多个值用于不同的实例时,这是错误的。 - 第二种方法要求调用者多次传递同一个变量,而该值在构造时可用。虽然比第一种方法更容易混淆,但这种方法并不理想。
- 第三种方法在代码中显示
myVar
的值是每个实例一个,并且不会更改。对于您在问题中描述的情况,这是最合乎逻辑的方法。
最简单、最清晰和最不容易出错的解决方案也是最快(或足够快)的,这在 Java 中很常见。
在担心速度之前,你应该问问自己;什么是最简单、最清晰和最不容易出错的方法?通过静态值传递值非常容易出错,尤其是当您拥有多线程应用程序时。不要这样做。如果您的程序无法运行,那么速度并不重要。
但是,在这种情况下,使用 static
字段也会造成混淆。调用者不清楚他们必须首先设置什么。如果你使用递归,这将使你的工作更加困难。
更糟糕的是,局部变量比静态字段更能优化。这意味着静态字段也更慢,可能更慢。
注意:为了防止 JIT 优化,JMH 使用 "blackhole" 作为结果值来阻止代码被优化掉,它使用 static
字段来做到这一点。
选项 3 可能是最好的,前提是值永远不会改变,尤其是如果您有多个值,但是如果值确实改变,它会变慢,因为您每次都会增加创建 Test
对象的开销, JIT 可能无法优化。
这个解决方案怎么样,使用更少的内存,没有创建实例。你需要一些方法。数据将存储在线程堆栈中,并减少线程上下文切换,如果您重用 ThreadPoolExecutor 等线程,则会消耗额外的时间。 如果可以为其他用例更改 myVar,最好将其作为参数添加到方法中。
public class Test {
public static void frequentlyUsedMultiThreadMethod(int myVar){
//read myVar
}
}