网站开发课程设计参考文献,沈阳男科医院哪家好哪个医院正规,wordpress 4.5.4,上海网站建设的网java 编写代码当我第一次写此博客时#xff0c;我的目的是向您介绍ThreadLocalRandom类#xff0c;它是Java 7中新增的用于生成随机数的类。 我在一系列微基准测试中分析了ThreadLocalRandom的性能#xff0c;以了解其在单线程环境中的性能。 结果相对令人惊讶#xff1a;尽… java 编写代码 当我第一次写此博客时我的目的是向您介绍ThreadLocalRandom类它是Java 7中新增的用于生成随机数的类。 我在一系列微基准测试中分析了ThreadLocalRandom的性能以了解其在单线程环境中的性能。 结果相对令人惊讶尽管代码非常相似但ThreadLocalRandom速度是Math.random()两倍 结果引起了我的兴趣我决定对此进行进一步的研究。 我已经记录了我的分析过程。 它是对分析步骤技术和一些JVM诊断工具的示例性介绍以了解小型代码段的性能差异。 使用上述工具集和技术的一些经验将使您能够为特定的Hotspot目标环境编写更快的Java代码。 好的这已经足够了让我们开始吧 我的机器是运行Windows XP的普通Intel 386 32位双核。 Math.random()处理Random的静态单例实例而ThreadLocalRandom - current() - nextDouble()处理ThreadLocalRandom的线程本地实例该实例是Random的子类。 ThreadLocal在对current()方法的每次调用中引入了变量查找的开销。 考虑到我刚才说的话那么在单个线程中它的速度是Math.random()的两倍这真的有点令人惊讶吗 我没想到会有如此大的差异。 同样我使用的是Heinz博客之一中介绍的微型基准测试框架。 Heinz开发的框架解决了在现代JVM上对Java程序进行基准测试时遇到的一些挑战。 这些挑战包括热身垃圾回收Java时间API的准确性测试准确性的验证等等。 这是我可运行的基准测试类 public class ThreadLocalRandomGenerator implements BenchmarkRunnable {private double r;Overridepublic void run() {r r ThreadLocalRandom.current().nextDouble();}public double getR() {return r;}Overridepublic Object getResult() {return r;}}public class MathRandomGenerator implements BenchmarkRunnable {private double r;Overridepublic void run() {r r Math.random();}public double getR() {return r;}Overridepublic Object getResult() {return r;}
} 让我们使用Heinz的框架运行基准测试 public class FirstBenchmark {private static ListBenchmarkRunnable benchmarkTargets Arrays.asList(new MathRandomGenerator(),new ThreadLocalRandomGenerator());public static void main(String[] args) {DecimalFormat df new DecimalFormat(#.##);for (BenchmarkRunnable runnable : benchmarkTargets) {Average average new PerformanceHarness().calculatePerf(new PerformanceChecker(1000, runnable), 5);System.out.println(Benchmark target: runnable.getClass().getSimpleName());System.out.println(Mean execution count: df.format(average.mean()));System.out.println(Standard deviation: df.format(average.stddev()));System.out.println(To avoid dead code coptimization: runnable.getResult());}}
} 注意为了确保JVM不会将代码标识为“死代码”我返回了一个字段变量并立即打印出基准测试的结果。 这就是为什么我的可运行类实现名为RunnableBenchmark的接口。 我已经运行了三次基准测试。 第一次运行是在默认模式下启用了内联和JIT优化 Benchmark target: MathRandomGenerator
Mean execution count: 14773594,4
Standard deviation: 180484,9
To avoid dead code coptimization: 6.4005410634212025E7
Benchmark target: ThreadLocalRandomGenerator
Mean execution count: 29861911,6
Standard deviation: 723934,46
To avoid dead code coptimization: 1.0155096190946539E8 然后再次不进行JIT优化VM选项-Xint Benchmark target: MathRandomGenerator
Mean execution count: 963226,2
Standard deviation: 5009,28
To avoid dead code coptimization: 3296912.509302683
Benchmark target: ThreadLocalRandomGenerator
Mean execution count: 1093147,4
Standard deviation: 491,15
To avoid dead code coptimization: 3811259.7334526842 最后一个测试是使用JIT优化但是使用-XX:MaxInlineSize0 它几乎禁用了内联 Benchmark target: MathRandomGenerator
Mean execution count: 13789245
Standard deviation: 200390,59
To avoid dead code coptimization: 4.802723374491231E7
Benchmark target: ThreadLocalRandomGenerator
Mean execution count: 24009159,8
Standard deviation: 149222,7
To avoid dead code coptimization: 8.378231170741305E7 让我们仔细地解释结果借助完整的JVM JIT优化 ThreadLocalRanom速度是Math.random()两倍。 关闭JIT优化表明两者的性能相同差。 方法内联似乎使性能相差30。 其他差异可能归因于其他优化技术 。 JIT编译器可以更有效地调整ThreadLocalRandom原因之一是ThreadLocalRandom.next()的改进实现。 public class Random implements java.io.Serializable {
...protected int next(int bits) {long oldseed, nextseed;AtomicLong seed this.seed;do {oldseed seed.get();nextseed (oldseed * multiplier addend) mask;} while (!seed.compareAndSet(oldseed, nextseed));return (int)(nextseed (48 - bits));}
...
}public class ThreadLocalRandom extends Random {
...protected int next(int bits) {rnd (rnd * multiplier addend) mask;return (int) (rnd (48-bits));}
...
} 第一个片段显示Random.next() 它在Math.random()的基准测试中大量使用。 与ThreadLocalRandom.next()相比该方法需要更多的指令尽管这两种方法都做同样的事情。 在Random类中 seed变量将全局共享状态存储到所有线程并且每次调用next()方法时都会更改。 因此需要AtomicLong安全地访问和更改对nextDouble()调用中的seed值。 另一方面 ThreadLocalRandom是–很好的–线程局部:-) next()方法不必是线程安全的可以使用普通的long变量作为种子值。 关于方法内联和ThreadLocalRandom 方法内联是一种非常有效的JIT优化。 在频繁执行的热路径中热点编译器决定将被调用方法子方法的代码内联到调用方方法父方法中。 内联具有重要的好处。 它大大降低了方法调用的动态频率从而节省了执行这些方法调用所需的时间。 但更重要的是内联会产生更大的代码块以供优化程序使用。 这就造成了一种情况大大提高了传统编译器优化的效率克服了提高Java编程语言性能的主要障碍。” 从Java 7开始您可以使用诊断JVM选项监视方法内联。 使用 -XX:UnlockDiagnosticVMOptions -XX:PrintInlining 运行代码将显示JIT编译器的内联工作。 以下是Math.random()基准测试输出的相关部分 13 java.util.Random::nextDouble (24 bytes) 3 java.util.Random::next (47 bytes) callee is too large 13 java.util.Random::next (47 bytes) callee is too large JIT编译器无法内联Random.next()中调用的Random.nextDouble() 。 这是ThreaLocalRandom.next()的内联输出 8 java.util.Random::nextDouble (24 bytes) 3 java.util.concurrent.ThreadLocalRandom::next (31 bytes) 13 java.util.concurrent.ThreadLocalRandom::next (31 bytes) 由于next()方法较短31个字节因此可以内联。 因为在两个基准测试中都强烈调用next()方法所以该日志表明方法内联可能是ThreadLocalRandom显着提高执行速度的原因之一。 为了验证并发现更多信息需要深入研究汇编代码。 使用Java 7 JDK可以将汇编代码打印到控制台中。 有关如何启用-XX:PrintAssembly VM选项的信息请参见此处 。 该选项将打印出JIT优化的代码这意味着您可以看到JVM实际执行的代码。 我已经将相关的汇编代码复制到下面的链接中。 此处的ThreadLocalRandomGenerator.run的汇编代码。 MathRandomGenerator.run的汇编代码在此处 。 Math.random 在此处调用的Random.next的汇编代码。 汇编代码是特定于机器的低级代码 比起bytecode读起来要复杂得多。 让我们尝试在我的基准测试中验证方法内联对性能的影响以及JIT编译器如何对待ThreadLocalRandom和Math.random 还有其他明显的区别吗 在ThreadLocalRandomGenerator.run() 没有对任何子例程如Random.nextDouble()或ThreatLocalRandom.next()过程调用。 对ThreadLocal.get()仅有一个虚拟的因此很昂贵方法调用请参阅ThreadLocalRandomGenerator.run()程序集的第35行。 其他所有代码都内联到ThreadLocalRandomGenerator.run() 。 在的情况下MathRandomGenerator.run()有两个虚拟方法调用到Random.next()见块B4线204页及以后中的汇编代码MathRandomGenerator.run() 这一事实证实了我们的怀疑即方法内联是导致性能差异的一个重要根本原因。 此外由于同步的麻烦 Random.next()需要的汇编指令要多得多并且有些昂贵这在执行速度方面也适得其反。 了解invokevirtual指令的开销 那么为什么虚拟方法调用昂贵且方法内联如此有效 invokevirtual指令的指针不是类实例中具体方法的偏移量。 编译器不知道类实例的内部布局。 相反它生成对实例方法的符号引用这些符号引用存储在运行时常量池中。 这些运行时常量池项在运行时解析以确定实际的方法位置。 这种动态运行时绑定需要验证准备和解决这可能会大大影响性能。 有关详细信息请参见JVM规范中的调用方法和链接 。 目前为止就这样了。 免责声明当然解决性能难题需要了解的主题列表无穷无尽。 除了微基准测试JIT优化方法内联java字节代码assemby语言等等之外还有很多东西要理解。 同样除了虚拟方法调用或昂贵的线程同步指令之外还有更多导致性能差异的根本原因。 但是我认为我介绍的主题是此类深入研究的一个很好的开始。 期待批评和愉快的评论 参考资料来自JCG合作伙伴 Niklas的“ Java 7如何编写非常快速的Java代码”。 翻译自: https://www.javacodegeeks.com/2012/01/java-7-how-to-write-really-fast-java.htmljava 编写代码