gpt4 book ai didi

java - 为什么在字段变量上同步并在同步块(synchronized block)内递增它会导致打印乱序?

转载 作者:行者123 更新时间:2023-12-03 12:48:44 24 4
gpt4 key购买 nike

我有一个简单的代码片段

public class ItemManager {

private Integer itemCount = 0;

public void incrementAndPrint() {
synchronized(this) {
System.out.println(++itemCount + " ");
}
}

public static void main(String[] args) {
ItemManager manager = new ItemManager();
ExecutorService executor = Executors.newFixedThreadPool(20);

for (int i = 0; i < 10; i++) {
executor.submit(manager::incrementAndPrint);
}
executor.shutdown();
}
}

按预期生成 1 2 3 4 5 6 7 8 9 10。我还可以使用 Object 实例创建另一个字段并锁定它

    private Integer itemCount = 0;
private Object lock = new Object();

public void incrementAndPrint() {
synchronized(lock) {
System.out.println(++itemCount + " ");
}
}

它还会按预期生成 1 2 3 4 5 6 7 8 9 10。

但是,如果我尝试锁定我想要递增和打印的同一个对象

    private Integer itemCount = 0;

public void incrementAndPrint() {
synchronized(itemCount) {
System.out.println(++itemCount + " ");
}
}

操作将保持原子性,但结果乱序:2 1 3 4 5 6 7 8 9 10。

我知道 synchronized(this) 或同步整个方法将解决我所有的问题。我只是不明白为什么我可以锁定一个字段(Object lock),但不能锁定另一个字段(Integer itemCount)? synchronized block 中的所有内容是否都应该被正确锁定,无论这个对象是什么,只要它是所有线程之间共享的单个对象?

最佳答案

Java 中的

Integer 是不可变的。当您调用 ++itemCount 时,您实际上执行了三个操作:首先,Integer 被拆箱为 int,其值为整数。然后,这个原语 int 递增,最后递增的 int 被自动装箱回一个 Integer。所以实际上,您最终拥有不同的 Integer 实例。由于您在不同的实例上进行同步,因此同步是没有意义的,并且您会看到乱序打印。

关于java - 为什么在字段变量上同步并在同步块(synchronized block)内递增它会导致打印乱序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65954179/

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