От 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
s являются потокобезопасными, я пропустил некоторые моменты? И как это исправить?
, вероятно, потому, что атомистические цепочки безопасны для себя, но вы смешиваете операции двух независимых атомных интеграторов. выбор из одного, а затем установка на другом. –