Java 为什么长文字的计算需要更多的时间?
对于简单的多线程代码,如下所示 关闭主线程需要Java 为什么长文字的计算需要更多的时间?,java,multithreading,Java,Multithreading,对于简单的多线程代码,如下所示 关闭主线程需要41338毫秒,始终具有类似的延迟 如果我将long替换为int,然后像i
41338毫秒
,始终具有类似的延迟
如果我将long
替换为int
,然后像i<0x7FFFFFFF
那样进行比较,则会持续28毫秒
,延迟类似
机器电源:运行64位JVM 1.6的DELL E6430 latitude 64位机器
公共类虚拟{
私有静态int NUM OF_线程=200;
私有静态线程[]线程=null;
公共静态无效循环(int i){
thread[i]=新线程(new Runnable(){
公开募捐{
整数计数=0;
用于(长i=0;i<0x7FFFFFFFL;++i){
计数++;
}
系统输出打印项次(计数);
}
});
线程[i].start();
}
公共静态void main(字符串[]args)引发InterruptedException{
线程=新线程[线程数];
long beginTime=System.nanoTime();
for(int i=0;i
我将0x7FFFFFL
的值解释为相当于0x7FFFFF
的值进行比较,即2147483647
请帮助我了解延迟的区别。代码不同。。。 以下是
int
版本的代码:
public void run();
Code:
0: iconst_0
1: istore_1
2: iconst_0
3: istore_2
4: iload_2
5: ldc #2 // int 2147483647
7: if_icmpge 19
10: iinc 1, 1
13: iinc 2, 1
16: goto 4
19: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
22: iload_1
23: invokevirtual #4 // Method java/io/PrintStream.println:(I)V
26: return
}
public void run();
Code:
0: iconst_0
1: istore_1
2: lconst_0
3: lstore_2
4: lload_2
5: ldc2_w #2 // long 2147483647l
8: lcmp
9: ifge 22
12: iinc 1, 1
15: lload_2
16: lconst_1
17: ladd
18: lstore_2
19: goto 4
22: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
25: iload_1
26: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
29: return
}
下面是long
版本的代码:
public void run();
Code:
0: iconst_0
1: istore_1
2: iconst_0
3: istore_2
4: iload_2
5: ldc #2 // int 2147483647
7: if_icmpge 19
10: iinc 1, 1
13: iinc 2, 1
16: goto 4
19: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
22: iload_1
23: invokevirtual #4 // Method java/io/PrintStream.println:(I)V
26: return
}
public void run();
Code:
0: iconst_0
1: istore_1
2: lconst_0
3: lstore_2
4: lload_2
5: ldc2_w #2 // long 2147483647l
8: lcmp
9: ifge 22
12: iinc 1, 1
15: lload_2
16: lconst_1
17: ladd
18: lstore_2
19: goto 4
22: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
25: iload_1
26: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
29: return
}
您可以看到所使用的JVM指令并不相同int
s递增,而long
s使用算术。大致上:int
代码使用寄存器,而不是long
寄存器
这至少可以解释我的电脑和你的电脑之间的差异
它使用java:
java version "1.8.0_20"
Java(TM) SE Runtime Environment (build 1.8.0_20-b26)
Java HotSpot(TM) 64-Bit Server VM (build 25.20-b23, mixed mode)
和javac
javac 1.8.0_20
在MacOSX 10.9平台上
我的JVM是64位的…代码不一样。。。 以下是
int
版本的代码:
public void run();
Code:
0: iconst_0
1: istore_1
2: iconst_0
3: istore_2
4: iload_2
5: ldc #2 // int 2147483647
7: if_icmpge 19
10: iinc 1, 1
13: iinc 2, 1
16: goto 4
19: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
22: iload_1
23: invokevirtual #4 // Method java/io/PrintStream.println:(I)V
26: return
}
public void run();
Code:
0: iconst_0
1: istore_1
2: lconst_0
3: lstore_2
4: lload_2
5: ldc2_w #2 // long 2147483647l
8: lcmp
9: ifge 22
12: iinc 1, 1
15: lload_2
16: lconst_1
17: ladd
18: lstore_2
19: goto 4
22: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
25: iload_1
26: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
29: return
}
下面是long
版本的代码:
public void run();
Code:
0: iconst_0
1: istore_1
2: iconst_0
3: istore_2
4: iload_2
5: ldc #2 // int 2147483647
7: if_icmpge 19
10: iinc 1, 1
13: iinc 2, 1
16: goto 4
19: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
22: iload_1
23: invokevirtual #4 // Method java/io/PrintStream.println:(I)V
26: return
}
public void run();
Code:
0: iconst_0
1: istore_1
2: lconst_0
3: lstore_2
4: lload_2
5: ldc2_w #2 // long 2147483647l
8: lcmp
9: ifge 22
12: iinc 1, 1
15: lload_2
16: lconst_1
17: ladd
18: lstore_2
19: goto 4
22: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
25: iload_1
26: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
29: return
}
您可以看到所使用的JVM指令并不相同int
s递增,而long
s使用算术。大致上:int
代码使用寄存器,而不是long
寄存器
这至少可以解释我的电脑和你的电脑之间的差异
它使用java:
java version "1.8.0_20"
Java(TM) SE Runtime Environment (build 1.8.0_20-b26)
Java HotSpot(TM) 64-Bit Server VM (build 25.20-b23, mixed mode)
和javac
javac 1.8.0_20
在MacOSX 10.9平台上
我的JVM是64位的…这不是进行基准测试的有用方法;你的数字将与实际表现相去甚远。您需要担心JIT预热之类的事情,这实际上意味着使用精心设计的基准测试工具,如卡钳或JMH。你不能从你正在进行的测量类型中得到任何有用的数字。你确定你没有在那里长时间不小心抛出一个额外的F吗?另外,如果你运行程序两次,第二次可能运行得更快。我怀疑如果你运行这十次,你会得到十个不同的结果。如果主线程在28毫秒内完成,那么它可能在调度任何其他线程之前完成。在Sun/Oracle JVM解释器中,Long和double值的实现相当笨拙。(每个值被分成两个堆栈槽。)如果你小心地“预热”JITC,你应该会看到更少的变化;你的数字将与实际表现相去甚远。您需要担心JIT预热之类的事情,这实际上意味着使用精心设计的基准测试工具,如卡钳或JMH。你不能从你正在进行的测量类型中得到任何有用的数字。你确定你没有在那里长时间不小心抛出一个额外的F吗?另外,如果你运行程序两次,第二次可能运行得更快。我怀疑如果你运行这十次,你会得到十个不同的结果。如果主线程在28毫秒内完成,那么它可能在调度任何其他线程之前完成。在Sun/Oracle JVM解释器中,Long和double值的实现相当笨拙。(每个值在两个堆栈槽之间分割。)如果您小心地“预热”JITC,您应该会看到更少的变化。但是请注意,一个好的JITC会“展平”大部分差异。请注意,这是由于int和long之间的差异造成的“Long literal”与此无关。@EJP——有一种特殊情况,javac必须对“small”
Long
literal(例如,5L
)执行ldc2\w
)而等效的int
代码将对iconst_5
执行文字加载。因此int
案例中offset4-16
的JVM指令和long
案例中offset4-19
的JVM指令在性能上产生了差异。JITC是如何进入画面的?我所知道的是,javac
将.java
编译成.class
和java.exe
在windows上解释并执行每个JVM指令。是的,最基本的任务是解释JVM指令,但JITC是运行时的编译器。基本思想是加速频繁使用的代码。然后“解释器”可以将JVM代码的一部分翻译成本机代码,然后再进行一些优化。但是请注意,一个好的JITC会“压平”大部分差异。请注意,这是由于int和long之间的差异造成的“Long literal”与此无关。@EJP——有一种特殊情况,javac必须对“small”Long
literal(例如,5L
)执行ldc2\w
,而等价的