Java多线程计数器不起作用。

huangapple go评论73阅读模式
英文:

Java multi threaded counter is not working

问题

我正在尝试使用Java多线程计数器。我首先尝试了没有任何同步的情况下观察竞争条件。但是我的计数器没有被工作线程递增。

代码 - 主方法

public static void main(String... args) {

    System.out.println("程序已启动");
    Integer sum = 0;
    System.out.println("初始总和:" + sum);

    for (int i = 0; i < 100; i++) {
        WorkerThread workerThread = new WorkerThread(sum, i);
        workerThread.run();
    }

    System.out.println("最终总和:" + sum);

}

代码 - WorkerThread 类

public class WorkerThread implements Runnable {

    private Integer localSum;

    public WorkerThread(Integer sum, int i){
        localSum = sum;
        System.out.println(localSum);
    }

    @Override
    public void run() {
        localSum += 1;
    }
}

我想知道为什么递增 localSum 不会影响到 Integer 包装对象 sumsum 的值仍然保持为 0。有人能帮我弄清楚如何将 Integer 包装对象传递给线程并递增原始值吗?

英文:

I am trying Java multi threaded counter. I first tried without any synchronisation to observe the race condition. But my counter is not incremented by worker threads.

Code - MAIN METHOD

public static void main(String... args) {

    System.out.println(&quot;Program started&quot;);
    Integer sum = 0;
    System.out.println(&quot;Initial Sum : &quot; + sum);

    for (int i = 0; i &lt; 100; i++) {
        WorkerThread workerThread = new WorkerThread(sum, i);
        workerThread.run();
    }

    System.out.println(&quot;Final Sum : &quot; + sum);

}

Code - WorkerThread class

public class WorkerThread implements Runnable {

    private Integer localSum;


    public WorkerThread(Integer sum, int i){
        localSum = sum;
        System.out.println(localSum);
    }

    @Override
    public void run() {
        localSum += 1;
    }
}

I wonder why incrementing localSum does not affect to Integer wrapper object sum.
The sum value stays at 0. Can anyone help me to figure out how to pass Integer wrapper into a thread and increment the original value?

答案1

得分: 4

问题在于 localSum += 1 并不是你想象的那样操作。

Integer 对象是不可变的:你不能改变 Integer 的值。localSum+=1 语句会创建一个 新的 Integer 实例,并将 localSum 变量更改为引用新实例。与此同时,main() 例程的 sum 变量将始终引用原始的不可变实例。

@Murat Karagöz 说过,"使用 AtomicInteger。" 这将解决 两个 问题:

  1. AtomicInteger 实例是可变的,以及
  2. ai.incrementAndGet() 操作和其他 AtomicInteger 操作是 线程安全 的。

你的程序,按照目前的写法,不需要线程安全性,但一旦你更改它以实际创建多个线程,就会需要线程安全性。

如果你将所有的 AtomicInteger 变量都声明为 final,这会有助于确保正确性。例如:

public class WorkerThread implements Runnable {
    private final AtomicInteger localSum;

    public WorkerThread(AtomicInteger sum, int i){
        localSum = sum;
        System.out.println(localSum.get());
    }
    ...
}

你不希望意外更改 localSum 字段的值(即,你不希望更改它指向的哪个 AtomicInteger 实例),你希望改变的是 AtomicInteger 实例本身。

英文:

The problem is that localSum += 1 does not do what you think it does.

Integer objects are immutable: You can not change the value of an Integer. The localSum+=1 statement creates a new Integer instance, and it changes the localSum variable to refer to the new instance. Meanwhile, the main() routine's sum variable always will refer to the original, immutable instance.

@Murat Karagöz said, "Use an AtomicInteger." That would solve two problems;

  1. AtomicInteger instances are mutable, and
  2. The ai.incrementAndGet() operation, and other AtomicInteger operations are thread safe.

Your program, as written, doesn't need thread safety, but it will need once you change it to actually create multiple threads.

It will help you to get it right if you make all of your AtomicInteger variables final. E.g.;

public class WorkerThread implements Runnable {
    private final AtomicInteger localSum;

    public WorkerThread(AtomicInteger sum, int i){
        localSum = sum;
        System.out.println(localSum.get());
    }
    ...
}

You don't want to accidentally change the value of the localSum field (i.e., you don't want to change which AtomicInteger instance it points to,) You want to mutate the AtomicInteger instance itself.

huangapple
  • 本文由 发表于 2020年7月23日 22:02:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/63056132.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定