gpt4 book ai didi

java - 为什么 i++ 不是原子的?

转载 作者:IT老高 更新时间:2023-10-28 11:32:21 31 4
gpt4 key购买 nike

为什么 i++ 在 Java 中不是原子的?

为了更深入地了解 Java,我尝试计算线程中循环的执行频率。

所以我用了一个

private static int total = 0;

在主类中。

我有两个线程。

  • 线程 1:打印 System.out.println("Hello from Thread 1!");
  • 线程 2:打印 System.out.println("Hello from Thread 2!");

我计算线程 1 和线程 2 打印的行数。但是线程 1 的行数 + 线程 2 的行数与打印出的总行数不匹配。

这是我的代码:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Test {

private static int total = 0;
private static int countT1 = 0;
private static int countT2 = 0;
private boolean run = true;

public Test() {
ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
newCachedThreadPool.execute(t1);
newCachedThreadPool.execute(t2);
try {
Thread.sleep(1000);
}
catch (InterruptedException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
run = false;
try {
Thread.sleep(1000);
}
catch (InterruptedException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println((countT1 + countT2 + " == " + total));
}

private Runnable t1 = new Runnable() {
@Override
public void run() {
while (run) {
total++;
countT1++;
System.out.println("Hello #" + countT1 + " from Thread 2! Total hello: " + total);
}
}
};

private Runnable t2 = new Runnable() {
@Override
public void run() {
while (run) {
total++;
countT2++;
System.out.println("Hello #" + countT2 + " from Thread 2! Total hello: " + total);
}
}
};

public static void main(String[] args) {
new Test();
}
}

最佳答案

i++在 Java 中可能不是原子性的,因为原子性是一个特殊要求,在 i++ 的大多数使用中不存在。 .这个要求有很大的开销:使增量操作原子化的成本很高;它涉及软件和硬件级别的同步,不需要以普通增量存在。

你可以提出 i++ 的论点应该设计和记录为专门执行原子增量,以便使用 i = i + 1 执行非原子增量.但是,这会破坏 Java、C 和 C++ 之间的“文化兼容性”。同样,它会带走熟悉类 C 语言的程序员认为理所当然的方便表示法,赋予它仅在有限情况下适用的特殊含义。

基本的 C 或 C++ 代码,如 for (i = 0; i < LIMIT; i++)将转换为 Java 为 for (i = 0; i < LIMIT; i = i + 1) ;因为使用原子 i++ 是不合适的.更糟糕的是,从 C 或其他类 C 语言到 Java 的程序员会使用 i++无论如何,导致不必要地使用原子指令。

即使在机器指令集级别,出于性能原因,增量类型的操作通常也不是原子的。在 x86 中,必须使用特殊指令“锁定前缀”来生成 inc指令原子:出于与上述相同的原因。如果 inc始终是原子的,当需要非原子公司时永远不会使用它;程序员和编译器会生成加载、加 1 和存储的代码,因为这样会更快。

在某些指令集架构中,没有原子 inc或者也许没有inc一点也不;要在 MIPS 上进行 atomic inc,您必须编写一个使用 ll 的软件循环。和 sc :加载链接和存储条件。加载链接读取单词,如果单词没有更改,则存储条件存储新值,否则失败(检测到并导致重试)。

关于java - 为什么 i++ 不是原子的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25168062/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com