我是 Java 多线程的新手,我编写了一些代码来了解它是如何工作的。我将 global = 0
作为全局 int 变量,并使用 for
循环初始化大量线程 (100) 以将 1 添加到我的全局变量。
在代码的末尾,结果应该是 100,但不是。我有时在代码末尾有 99 或任何其他数字(大约 100)。所以我的问题是,为什么线程在它们之间“打架”并且总和不正确?
public class test extends Thread {
public static int global =0;
public static void main(String[] args) throws Exception {
for(int i=0;i<100;i++){
String stream = String.valueOf(i);
new test2(stream).start();
}
Thread.sleep(1000);
System.out.println(global);
}
public test(String str) {
super(str);
}
public void run() {
int a = Integer.parseInt(getName());
global = global+1;
System.out.println("El hilo "+a+" tiene el número "+global);
}
}
我知道我不需要 int a = Integer.parseInt(getName());
,但我假装你将来会用到这个名字。而且,如果我现在删除它,结果无论如何都是错误的。
最佳答案
这是一个经典的竞争条件。
你的一个线程,称之为“A”,读取了值 global
,比如说 10
,并向它添加了 1
,但它没有将值 11
存储回 global
。
你的另一个线程,称之为“B”,现在正在读取 global
的“旧”值,10
,它正在添加 1
并将值 11
存储回 global
。
然后线程“A”最终被允许将其值 11
存储回 global
。发生了两次增量,但最终结果是实际上只发生了一次增量。
发生这种情况是因为递增值并将其存储回变量的操作不是原子。这意味着有多个单独的操作,如果被中断,可能会产生不正确的结果。
您必须创建一个synchronized
block 来强制执行原子操作。您可以锁定类对象本身。
synchronized (test.class) {
global = global+1;
}
作为替代方案,您可以将全局
变量设为AtomicInteger
。 ,它会为您处理原子更新。
关于java - JAVA中多线程的全局求和错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29632775/