휘발성 부울이 달성 할 수없는 AtomicBoolean은 무엇입니까?
휘발성 부울이 달성 할 수없는 AtomicBoolean은 무엇입니까?
답변:
그들은 완전히 다릅니다. volatile
정수 의이 예제를 고려하십시오 .
volatile int i = 0;
void incIBy5() {
i += 5;
}
두 개의 스레드가 동시에 함수를 호출하는 경우 i
컴파일 된 코드는 다음과 비슷하기 때문에 나중에 5 일 수 있습니다 (동기화 할 수는 제외 int
).
void incIBy5() {
int temp;
synchronized(i) { temp = i }
synchronized(i) { i = temp + 5 }
}
변수가 일시적인 경우 변수에 대한 모든 원자 적 접근은 동기화되지만 실제로 원자 적 접근으로 자격이되는 것이 항상 명확한 것은 아닙니다. Atomic*
객체를 사용하면 모든 방법이 "원자"임을 보장합니다.
따라서 AtomicInteger
and 를 사용 getAndAdd(int delta)
하면 결과가임을 확신 할 수 있습니다 10
. 같은 방식으로 두 스레드가 boolean
동시에 변수를 무효화하면 AtomicBoolean
나중에 원래 값을 갖는지 volatile boolean
확인할 수 있습니다.
따라서 필드를 수정하는 스레드 가 둘 이상 있을 때마다 원자를 만들거나 명시 적 동기화를 사용해야합니다.
목적은 volatile
다릅니다. 이 예제를 고려하십시오
volatile boolean stop = false;
void loop() {
while (!stop) { ... }
}
void stop() { stop = true; }
스레드가 실행 중이고 loop()
다른 스레드 호출이있는 경우stop()
가있는 경우 volatile
첫 번째 스레드가 stop 값을 캐시 할 수 있으므로 생략하면 무한 루프가 발생할 수 있습니다. 여기서는 volatile
컴파일러에 대한 힌트 역할을하여 최적화에 좀 더주의를 기울입니다.
volatile
. 문제는 volatile boolean
vs 에 관한 것 AtomicBoolean
입니다.
volatile boolean
충분합니다. 작가가 많을 경우가 필요할 수 있습니다 AtomicBoolean
.
해당 필드가 소유자 스레드에 의해서만 업데이트되고 값이 다른 스레드에서만 읽 히면 휘발성 필드를 사용합니다. 관찰자가 많지만 게시자가 하나 인 게시 / 구독 시나리오라고 생각할 수 있습니다. 그러나 해당 관찰자가 필드 값을 기반으로 일부 논리를 수행 한 다음 새 값을 되돌려 야하는 경우 Atomic * vars 또는 locks 또는 동기화 된 블록을 사용하여 가장 적합합니다. 많은 동시 시나리오에서 값을 가져오고 다른 값과 비교하고 필요한 경우 업데이트하므로 Atomic * 클래스에 compareAndSet 및 getAndSet 메소드가 존재합니다.
java.util.concurrent.atomic 패키지 의 JavaDocs에서 Atomic 클래스 목록과 작동 방식에 대한 훌륭한 설명을 확인하십시오 (잠금이 없음을 알게되어 잠금 또는 동기화 된 블록에 비해 유리합니다).
boolean
var를 수정하면 을 선택해야한다고 설명하고 싶습니다 volatile boolean
.
당신은 할 수 없어 compareAndSet
, getAndSet
휘발성 부울와 원자 작업으로 (물론하지 않는 한 당신은 그것을 동기화).
AtomicBoolean
synchronized
블록 을 사용할 필요없이 원자 적으로 복합 연산을 수행하는 메소드가 있습니다 . 반면 volatile boolean
에 synchronized
블록 내에서 복합 작업을 수행하는 경우에만 복합 작업을 수행 할 수 있습니다 .
읽기 / 쓰기의 메모리 효과 는 각각 및 방법 과 volatile boolean
동일하다 .get
set
AtomicBoolean
예를 들어,이 compareAndSet
방법은 원자 적으로 다음을 수행합니다 ( synchronized
블록 없이 ).
if (value == expectedValue) {
value = newValue;
return true;
} else {
return false;
}
따라서이 compareAndSet
메소드를 사용하면 여러 스레드에서 호출 된 경우에도 한 번만 실행될 수있는 코드를 작성할 수 있습니다. 예를 들면 다음과 같습니다.
final AtomicBoolean isJobDone = new AtomicBoolean(false);
...
if (isJobDone.compareAndSet(false, true)) {
listener.notifyJobDone();
}
보장 만 (다른 스레드 세트에게 없다고 가정 한 번 청취자에게 통지 AtomicBoolean
다시 false
는로 설정되는 후 다시을 true
).
volatile
키워드는 해당 변수를 공유하는 스레드 간의 관계가 발생하기 전에 보장합니다. 부울 변수에 액세스하는 동안 2 개 이상의 스레드가 서로 인터럽트하지 않는다는 보장은 없습니다.
Atomic*
클래스는 랩 volatile
필드.
휘발성 부울 대 원자 부울
Atomic * 클래스는 동일한 유형의 휘발성 프리미티브를 래핑합니다. 출처에서 :
public class AtomicLong extends Number implements java.io.Serializable {
...
private volatile long value;
...
public final long get() {
return value;
}
...
public final void set(long newValue) {
value = newValue;
}
따라서 당신이하고있는 모든 것이 Atomic *을 가져오고 설정하는 것이라면 대신 휘발성 필드가있을 수 있습니다.
휘발성 부울이 달성 할 수없는 AtomicBoolean은 무엇입니까?
Atomic * 클래스는 다음과 같은 고급 기능을 제공하는 메소드를 제공합니다 incrementAndGet()
.compareAndSet()
및 잠금없이 여러 작업 (GET / 증가 / 세트, 테스트 / 세트)를 구현 다른 사람을. 이것이 Atomic * 클래스가 매우 강력한 이유입니다.
예를 들어, 여러 스레드가를 사용하여 다음 코드를 사용하는 경우 실제로는 get, 증가 및 설정 과 같은 ++
경쟁 조건이 있습니다 ++
.
private volatile value;
...
// race conditions here
value++;
그러나 다음 코드는 다중 스레드 환경에서 잠금없이 안전하게 작동합니다.
private final AtomicLong value = new AtomicLong();
...
value.incrementAndGet();
또한 Atomic * 클래스를 사용하여 휘발성 필드를 감싸는 것이 객체 관점에서 중요한 공유 리소스를 캡슐화하는 좋은 방법이라는 점에 유의해야합니다. 이것은 개발자가 필드에 문제를 일으킬 가능성이 공유되지 않는다고 가정 할 때 필드를 처리 할 수 없다는 것을 의미합니다. 또는 경쟁 조건을 도입하는 다른 코드.
클래스 레벨 변수에 액세스하는 스레드가 여러 개인 경우 각 스레드는 스레드 로컬 캐시에 해당 변수의 사본을 유지할 수 있습니다.
변수를 휘발성으로 만들면 스레드가 스레드 로컬 캐시에 변수 사본을 유지하지 못하게됩니다.
원자 변수는 다르며 값을 원자 적으로 수정할 수 있습니다.
부울 프리미티브 유형은 쓰기 및 읽기 작업에 원자 적이며, 휘발성으로 인해 발생하는 원칙을 보장합니다. 따라서 간단한 get () 및 set ()이 필요한 경우 AtomicBoolean이 필요하지 않습니다.
반면에 변수 값을 설정하기 전에 몇 가지 검사를 구현해야하는 경우 (예 : "true 인 경우 false로 설정")이 작업을 원자 적으로 수행해야합니다.이 경우 compareAndSet 및 기타 메소드를 사용하십시오. AtomicBoolean, volatile boolean으로이 논리를 구현하려고하면 값이 get과 set 사이에서 변경되지 않았는지 확인하기 위해 동기화가 필요합니다.
IDIOM을 기억하십시오-
READ-MODIFY- WRITE 휘발성으로 달성 할 수없는 쓰기
volatile
소유자 스레드가 필드 값을 업데이트 할 수 있고 다른 스레드 만 읽을 수있는 경우에만 작동합니다.
부울을 수정하는 스레드가 하나만있는 경우 휘발성 부울을 사용할 수 있습니다 (일반적으로 stop
스레드의 메인 루프에서 확인 된 변수 를 정의하기 위해 수행 ).
그러나 부울을 수정하는 스레드가 여러 개인 경우을 사용해야합니다 AtomicBoolean
. 그렇지 않으면 다음 코드는 안전하지 않습니다.
boolean r = !myVolatileBoolean;
이 작업은 두 단계로 수행됩니다.
다른 스레드가 #1
와 사이의 값을 수정하면 2#
잘못된 결과가 발생할 수 있습니다. AtomicBoolean
방법은 단계적 으로 수행 #1
하여 #2
원자 적 으로이 문제를 피합니다 .
둘 다 동일한 개념이지만 원자 부울에서는 CPU 스위치가 사이에 발생할 경우 작업에 원 자성을 제공합니다.