java - JAVA中多线程的全局求和错误

标签 java

我是 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/

相关文章:

java - 实例变量和构造函数

java - 当套接字被接受时,我怎样才能关闭这个对话框?

java - 如何制作通用的jpa存储库?我应该这样做吗?为什么?

Maven/Jenkins java.lang.UnsupportedClassVersionError : Unsupported major. 次要版本 51.0

java - 在 XML 中初始化 TableLayout 并以编程方式填充它 - Android (java)

在处理中使用自定义类的 java.lang.NullPointerException

java - 有没有更简洁的方法来编写这段 Java 代码?

java - SonarQube 5.4 - StartSonar.bat - OutOfMemoryError : Java heap space

java - Eclipse 中测试用例的命名约定

java - 调用 hibernate session.get 方法