【发布时间】:2014-03-18 10:07:50
【问题描述】:
来自 Java 并发实践:
package net.jcip.examples;
import java.util.concurrent.atomic.*;
/**
* NumberRange
* <p/>
* Number range class that does not sufficiently protect its invariants
*
* @author Brian Goetz and Tim Peierls
*/
public class NumberRange {
// INVARIANT: lower <= upper
private final AtomicInteger lower = new AtomicInteger(0);
private final AtomicInteger upper = new AtomicInteger(0);
public void setLower(int i) {
// Warning -- unsafe check-then-act
if (i > upper.get())
throw new IllegalArgumentException("can't set lower to " + i + " > upper");
lower.set(i);
}
public void setUpper(int i) {
// Warning -- unsafe check-then-act
if (i < lower.get())
throw new IllegalArgumentException("can't set upper to " + i + " < lower");
upper.set(i);
}
public boolean isInRange(int i) {
return (i >= lower.get() && i <= upper.get());
}
}
它说“setLower 和 setUpper 都是 check-then-act 序列,但它们没有使用足够的锁定来使它们成为原子。如果数字范围保持 (0, 10),并且一个线程调用 setLower(5) 而另一个线程调用 setUpper(4),则在一些不幸的时机下,两者都将通过设置器中的检查,并且将应用两个修改。结果是范围现在保持 (5, 4) 无效状态。”
如果AtomicIntegers 是线程安全的,怎么会发生这种情况,我是否遗漏了一些要点?以及如何解决这个问题?
【问题讨论】:
-
可能是因为原子整数对自己是安全的,但是您正在混合两个独立原子整数的操作。从一个获取,然后在另一个上设置。
标签: java concurrency thread-safety