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
案例中offset
4-16
的JVM指令和
long
案例中offset
4-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
,而等价的