gpt4 book ai didi

java - 非同步i++是否重叠?

转载 作者:行者123 更新时间:2023-12-01 19:34:41 24 4
gpt4 key购买 nike

在尝试了解 Java 多线程基础知识时,我遇到了一个我无法理解的情况。社区,请分享您的经验为什么会发生这种情况:我有一个可运行的:

class ImproperStateWorker implements Runnable {
private int val = 0;
@Override
public void run() {
//Where are missing ticks?
for (int i = 0; i < 1000; i++) {
val++;
Thread.yield();
val++;
}
showDataState();
}

public void showDataState() {
System.out.print(Thread.currentThread() + " ; ");
System.out.println(val);
}
}

通过以下方式启动:

public class ImproperState {
public static void main(String[] args) {
ImproperStateWorker worker = new ImproperStateWorker();
for (int i = 0; i < 2; i++) {
Thread thread = new Thread(worker);
thread.start();
}
}

}

我理解这个想法是通过使用 synchronized() {...} 等使两个增量操作原子化。但我对以下内容感到困惑:为什么运行这两个 Runnables(不同步)不会产生 4000 的一致结果(每个任务 1000 x 2 增量)?无论两个任务之间的上下文如何切换,我预计每个任务将执行 2000 个增量,我不在乎顺序是什么。

但是,程序输出给出约 3.5K。我能想到的唯一想法是,出现“缺失”增量是因为其中一些增量是同时进行的,因此从两个线程调用的 val++ 实际上将值增加了 1。但这是一个非常模糊的假设。感谢您分享您的经验。

最佳答案

您的代码中有竞争条件。考虑以下可能的交错:

  1. 线程 1:读取 val0
  2. 线程 1:递增 01
  3. 线程 1:写入 val1
  4. 线程 1:读取 val1
  5. 线程 1:增量 12
  6. 线程 1:写入 val2
  7. 线程 2:读取 val2
  8. 线程 2:增量 23
  9. 线程 2:写入 val3
  10. 线程 2:读取 val3
  11. 线程 2:增量 34
  12. 线程 2:写入 val4
  13. 结束状态:val == 4

一切都很好。但是,请考虑这种同样可能的交错:

  1. 线程 1:读取 val0
  2. 线程 2:读取 val0
  3. 线程 1:递增 01
  4. 线程 2:增量 01
  5. 线程 1:写入 val1
  6. 线程 2:写入 val1
  7. 线程 1:读取 val1
  8. 线程 2:读取 val1
  9. 线程 1:增量 12
  10. 线程 2:增量 12
  11. 线程 1:写入 val2
  12. 线程 2:写入 val2
  13. 结束状态:val == 2

哎呀!

在您的问题中编写的代码中,结果可以是 20004000 之间的任何

解决此问题的一种方法是使用 AtomicIntegerAtomicInteger.getAndIncrement()AtomicInteger.incrementAndGet() (在您的情况下,哪个并不重要,因为您忽略了返回值;后缀 val++ 的正确等效项将是 val.getAndIncrement()),如下所示 (你只需要改变三个地方,不包括导入。):

import java.util.concurrent.atomic.AtomicInteger;

class FixedStateWorker implements Runnable {
private AtomicInteger val = new AtomicInteger();
// ↑↑↑↑↑↑↑↑↑↑↑↑↑ ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

@Override
public void run() {
for (int i = 0; i < 1000; i++) {
val.getAndIncrement();
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
Thread.yield();
val.getAndIncrement();
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
}
showDataState();
}
}

关于java - 非同步i++是否重叠?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58269532/

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