青岛科友网站建设网络公司,网络营销八大职能,dede购物网站,wordpress 兼容php7总览 许多多线程代码开发人员都熟悉这样的想法#xff0c;即不同的线程可以对持有的值有不同的看法#xff0c;这不是唯一的原因#xff0c;即如果线程不安全#xff0c;它可能不会看到更改。 JIT本身可以发挥作用。 为什么不同的线程看到不同的值#xff1f; 当您有多个… 总览 许多多线程代码开发人员都熟悉这样的想法即不同的线程可以对持有的值有不同的看法这不是唯一的原因即如果线程不安全它可能不会看到更改。 JIT本身可以发挥作用。 为什么不同的线程看到不同的值 当您有多个线程时它们将尝试例如通过尝试访问同一内存来最小化它们将交互的数量。 为此他们有一个单独的 本地副本例如在1级缓存中。 该缓存通常最终是一致的。 我看到两个线程看到不同值的短时间介于一微秒到十毫秒之间。 最终线程被上下文切换缓存被清除或更新。 无法保证何时会发生这种情况但几乎总是不到一秒钟。 JIT如何发挥作用 Java内存模型说不能保证不是线程安全的字段将看到更新。 这允许JIT进行优化将仅读取而不写入的值有效地内联到代码中。 这意味着即使更新了缓存更改也可能不会反映在代码中。 一个例子 该代码将一直运行直到将布尔值设置为false为止。 static class MyTask implements Runnable {private final int loopTimes;private boolean running true;boolean stopped false;public MyTask(int loopTimes) {this.loopTimes loopTimes;}Overridepublic void run() {try {while (running) {longCalculation();}} finally {stopped true;}}private void longCalculation() {for (int i 1; i loopTimes; i)if (Math.log10(i) 0)throw new AssertionError();}
}public static void main(String... args) throws InterruptedException {int loopTimes Integer.parseInt(args[0]);MyTask task new MyTask(loopTimes);Thread thread new Thread(task);thread.setDaemon(true);thread.start();TimeUnit.MILLISECONDS.sleep(100);task.running false;for (int i 0; i 200; i) {TimeUnit.MILLISECONDS.sleep(500);System.out.println(stopped task.stopped);if (task.stopped)break;}
} 此代码反复执行一些对内存没有影响的工作。 它唯一的区别是需要多长时间。 通过花费更长的时间它将确定在运行之前或之后将run中的代码优化为false。 如果我使用10或100和-XX PrintCompilation运行此命令则会看到 111 1 java.lang.String::hashCode (55 bytes)
112 2 java.lang.String::charAt (29 bytes)
135 3 vanilla.java.perfeg.threads.OptimisationMain$MyTask :longCalculation (35 bytes)
204 1 % ! vanilla.java.perfeg.threads.OptimisationMain$MyTask :run 0 (31 bytes)
stopped false
stopped false
stopped false
stopped false
... many deleted ...
stopped false
stopped false
stopped false
stopped false
stopped false 如果我用1000运行它您会看到run尚未编译并且线程停止 112 1 java.lang.String::hashCode (55 bytes)
112 2 java.lang.String::charAt (29 bytes)
133 3 vanilla.java.perfeg.threads.OptimisationMain $MyTask::longCalculation (35 bytes)
135 1 % vanilla.java.perfeg.threads.OptimisationMain $MyTask::longCalculation 2 (35 bytes)
stopped true 一旦线程被编译即使线程将进行多次上下文切换等更改也永远不会被看到。 如何解决这个问题 简单的解决方案是使该字段易变。 这将确保该字段的值是一致的而不仅仅是最终一致的这就是缓存可能为您执行的操作。 结论 虽然有许多类似的问题示例 为什么我的线程没有停止 答案更多与Java内存模型有关Java内存模型允许JIT“内联”它执行硬件的字段并在不同的缓存中具有多个数据副本。 参考 Vanilla Java博客上的JCG合作伙伴 Peter Lawrey提供的Java内存模型和优化 。 翻译自: https://www.javacodegeeks.com/2013/01/java-memory-model-and-optimisation-2.html