使用 Atomic 和无限循环在 JAVA 中进行同步
Using Atomic and infinite loop to do synchronisation in JAVA
考虑以下代码
static AtomicBoolean initialized = new AtomicBoolean(false);
static AtomicBoolean initStarted= new AtomicBoolean(false);
public static void init() {
if (!initialized.get() && !initStarted.getAndSet(true)) {
doInitialization();
initialized.set(true);
}
// start waiting
while (!initialized.get());
// finished waiting
doMoreStuff();
}
它实现了我想要确保在 doInitialization()
完成之前不调用 doMoreStuff()
并且只有第一个线程应该调用 doInitialization()
.
我的问题是,这与对整个 init()
方法使用 synchronized
块相比如何?
我看到 AtomicReference 也使用无限循环(a.k.a 忙等待)浪费 CPU 周期来做更新(见 AtomicReference#getAndUpdate()
),所以可能还不错在这里作为同步方法做同样的事情?
如果无限循环如此糟糕(例如浪费 CPU 循环)那么为什么 AtomicReference 不使用 synchronized
来停止或唤醒线程?
AtomicReference#getAndUpdate 未使用忙等待阻塞,直到外部条件发生变化。
134 * Atomically sets to the given value and returns the old value.
135 *
136 * @param newValue the new value
137 * @return the previous value
138 */
139 public final V getAndSet(V newValue) {
140 while (true) {
141 V x = get();
142 if (compareAndSet(x, newValue))
143 return x;
144 }
145 }
循环预期 运行 只有一次,除非在争用的情况下。
compareAndSet
失败的唯一方法是另一个线程在同一时间做同样的事情。
这称为 "retry-loop",应该只执行很少的次数(大约一次)。
AtomicBoolean.getAndSet 如果您只想允许单个线程访问特定块,就像您所做的那样,但我不建议在 if-statement 中与其他变量一起使用它可能会改变,即使这种情况可能是安全的。然而,你的 while 循环在等待时消耗了 100% CPU,所以我建议你改用 CountDownLatch。
AtomicBoolean initialized = new AtomicBoolean(false);
CountDownLatch lock = new CountDownLatch(1);
public void init() throws InterruptedException {
if (!initialized.getAndSet(true)) {
doInitialization();
lock.countDown();
}
// start waiting
lock.await();
// finished waiting
doMoreStuff();
}
考虑以下代码
static AtomicBoolean initialized = new AtomicBoolean(false);
static AtomicBoolean initStarted= new AtomicBoolean(false);
public static void init() {
if (!initialized.get() && !initStarted.getAndSet(true)) {
doInitialization();
initialized.set(true);
}
// start waiting
while (!initialized.get());
// finished waiting
doMoreStuff();
}
它实现了我想要确保在 doInitialization()
完成之前不调用 doMoreStuff()
并且只有第一个线程应该调用 doInitialization()
.
我的问题是,这与对整个 init()
方法使用 synchronized
块相比如何?
我看到 AtomicReference 也使用无限循环(a.k.a 忙等待)浪费 CPU 周期来做更新(见 AtomicReference#getAndUpdate()
),所以可能还不错在这里作为同步方法做同样的事情?
如果无限循环如此糟糕(例如浪费 CPU 循环)那么为什么 AtomicReference 不使用 synchronized
来停止或唤醒线程?
AtomicReference#getAndUpdate 未使用忙等待阻塞,直到外部条件发生变化。
134 * Atomically sets to the given value and returns the old value.
135 *
136 * @param newValue the new value
137 * @return the previous value
138 */
139 public final V getAndSet(V newValue) {
140 while (true) {
141 V x = get();
142 if (compareAndSet(x, newValue))
143 return x;
144 }
145 }
循环预期 运行 只有一次,除非在争用的情况下。
compareAndSet
失败的唯一方法是另一个线程在同一时间做同样的事情。
这称为 "retry-loop",应该只执行很少的次数(大约一次)。
AtomicBoolean.getAndSet 如果您只想允许单个线程访问特定块,就像您所做的那样,但我不建议在 if-statement 中与其他变量一起使用它可能会改变,即使这种情况可能是安全的。然而,你的 while 循环在等待时消耗了 100% CPU,所以我建议你改用 CountDownLatch。
AtomicBoolean initialized = new AtomicBoolean(false);
CountDownLatch lock = new CountDownLatch(1);
public void init() throws InterruptedException {
if (!initialized.getAndSet(true)) {
doInitialization();
lock.countDown();
}
// start waiting
lock.await();
// finished waiting
doMoreStuff();
}