gpt4 book ai didi

java - 同步您正在修改的静态字段是否会使您的代码线程安全?

转载 作者:行者123 更新时间:2023-12-01 06:48:40 25 4
gpt4 key购买 nike

class A {
private static BigInteger staticCode = BigInteger.ZERO;
private BigInteger code;
public A() {
synchronized(staticCode) {
staticCode = staticCode.plus(BigInteger.ONE);
code = staticCode;
}
}

}

无论如何,我都不是并发方面的专家。有人可以向我解释为什么上面提供的类不是线程安全的吗?

哪些情况会导致竞争状况?我的思考过程是,如果我们创建该类的 10 个实例,每个实例都将在 staticCode 的不同值上同步,这就是它是线程安全的原因,但有人告诉我事实并非如此。但为什么?

我知道我们可以在 .class 上进行同步,并且它肯定是线程安全的,但我仍然想了解这种特殊情况。

最佳答案

Does synchronizing on the static field that you are modifying make your code thread safe?

不,因为您要重新分配它。 (*)

一旦进行重新分配,您实际上就失去了访问staticCode的互斥性。字段。

  • 任何已经在 synchronized 处等待的线程分配之前的阻塞将继续等待。
  • 任何到达 synchronized 的线程重新分配之后但重新分配线程离开之前的 block 将尝试在 staticCode值上进行同步.

    比没有互斥这一事实更微妙的一点是,您还会丢失同步块(synchronized block)结束和下一次执行开始之间的发生时间。这意味着您无法保证更新值的可见性,因此您可能会生成 A 的多个实例。与相同的code .

在非最终成员上进行同步不是一个好主意。如果您不想在 A.class 上同步,您可以定义要同步的辅助成员:

class A {
private static final Object lock = new Object();
private static BigInteger staticCode = BigInteger.ZERO;

public A() {
synchronized (lock) {
staticCode = ...
}
}
}

这保留了 staticCode 的可变性,但允许正确的互斥。

但是,Atomic*类会更容易,因为您避免了同步的需要(例如 AtomicIntegerAtomicLong - 但如果您真的认为您将拥有超过 2^63 的东西,您可以使用 AtomicReference<BigInteger> ):

class A {
private static final Object lock = new Object();
private static AtomicReference<BigInteger> staticCode = new AtomicReference<>(BigInteger.ZERO);

public A() {
BigInteger code;
do {
code = staticCode.get();
} while (!staticCode.compareAndSet(code, code.add(BigInteger.ONE)));
this.code = code;

// Even easier with AtomicInteger/Long:
// this.code = BigInteger.valueOf(staticCode.incrementAndGet());
}
}
<小时/>

(*) 但无论如何,请放弃自动同步使某些东西线程安全的概念。一方面,您需要准确定义“线程安全”的含义;但是,您需要了解同步实际上为您提供了什么,以便评估这些东西是否满足您的线程安全要求。

关于java - 同步您正在修改的静态字段是否会使您的代码线程安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60423099/

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