在实践中来自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都是检查-然后动作序列,但它们没有使用足够的锁定使它们具有原子性。如果数字范围保持在(0,10),而一个线程调用setLower(5),而另一个线程调用setUpper(4),则带有一些不吉利的时间的线程都将通过设置器中的检查,并且都将应用这两种修改。结果是,范围现在保持(5,4)无效状态。“
如果AtomicInteger是线程安全的,那么它怎么会发生呢?以及如何解决这个问题?
发布于 2014-02-18 15:33:06
AtomicInteger的参与与您问题的线程安全性无关。
以下是问题所在:
步骤1和步骤2可以是单独的原子化的,但是它们一起形成两个步骤,非原子的动作。
以下是可能发生的情况:
每个单独的步骤本质上都是原子的,但是步骤的集合不是原子的。
用于此的java解决方案是:
请确保使用相同的对象引用来同步上值和下值的所有设置。
发布于 2014-02-18 15:42:16
让我们创建一个对象:
NumberRange nr= new NumberRange();线程A:
nr.setLower(-1); //A1线程B:
nr.setLower(-3); //B1
nr.setUpper(-2); //B2执行顺序: B1,然后是A1和B2,同时:如果线程B在A (-3 < -2)之前通过检查,然后A在B设置值(-1 < 0)之前通过检查,则此代码不会抛出任何错误,因为您的方法不是原子的。检查是原子的,set方法也是原子的,但是总共有两个原子步骤,而不是一个。
https://stackoverflow.com/questions/21857424
复制相似问题