JAVA中多线程的全局总和错误

时间:2015-04-14 16:35:54

标签: 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());,但我假装你将来使用这个名字。并且,如果我现在删除它,结果是错误的。

4 个答案:

答案 0 :(得分:13)

这是一种典型的竞争条件。

您的一个主题,称为“A”,已读取值global,说10,并向其添加1,但它尚未存储值{ {1}}返回11

你的另一个主题,称之为“B”,现在正在读取globalglobal的“旧”值,它正在向其添加10,并存储该值1返回11

然后,最后允许线程“A”将其值global存储回11。已经发生了两次增量,但最终结果是只有一次增量有效发生。

这是因为递增值并将其存储回变量的操作不是 atomic 。这意味着有多个单独的操作,如果被中断,可能会产生不正确的结果。

您必须创建一个global块以强制执行原子操作。您可以锁定类对象本身。

synchronized

作为替代方案,您可以将synchronized (test.class) { global = global+1; } 变量设为AtomicInteger,为您处理原子更新。

答案 1 :(得分:7)

那是因为

global = global+1;

不是原子操作。它包含在

  • 读取全球的价值,
  • 计算递增的值
  • 将结果分配给全局

因此,由于线程并发执行,您可能会遇到竞争条件:

  • 主题1读取34
  • 主题2读取34
  • 线程1计算递增的值
  • 线程2计算递增的值
  • 主题1将35分配给全局
  • 主题2将35分配给全局

多线程就是要确保正确修改共享状态。您需要同步对全局变量的每次访问以使其更改为原子。另一种方法是使用AtomicInteger,它允许以原子方式递增。

答案 2 :(得分:3)

以下语句不是线程安全的:

global = global+1;

想象一下这种情况:

线程#1到达此声明。它的内容为global 0。此时,线程#2到达相同的语句。它会显示global,但仍为0。现在,线程#1将1加0并将{1}}中的总数1保存。线程#2继续,添加1到0并将总计1保存到global


答案 3 :(得分:1)

为了使线程安全,最简单的方法是同步访问&#34; global&#34;通过某事。例如,您的类本身(也是Object)

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 test(stream).start();
    }
    Thread.sleep(1000);
    System.out.println(global);
}

public test(String str) {
    super(str);
}

public void run() {
    int a = Integer.parseInt(getName());
    synchronized (test.class) {
        global = global + 1;
    }
    System.out.println("El hilo " + a + " tiene el número " + global);
}

}