휘발성 부울 대 원자 부울


244

휘발성 부울이 달성 할 수없는 AtomicBoolean은 무엇입니까?


16
"각각의 한계는 무엇입니까?"에 대한보다 미묘한 답변을 찾고있었습니다. 예를 들어, is가 하나의 스레드에 의해 설정되고 하나 이상의 다른 스레드에 의해 읽힌 플래그 인 경우 AtomicBoolean이 필요하지 않습니다. 그러나이 답변에서 볼 수 있듯이 스레드가 여러 스레드에서 변수를 공유하고 쓰기 결과를 읽을 수있는 경우 AtomicBoolean은 CAS 유형 비 잠금 작업을 실행합니다. 사실 여기에서 약간 배우고 있습니다. 바라건대, 다른 사람들도 도움이 될 것입니다.
JeffV


휘발성 부울은 경쟁 조건을 처리하기 위해 명시 적 동기화가 필요합니다. 즉, 증분 / 감소 카운터 또는 부울 뒤집기 등 여러 스레드에 의해 업데이트되는 공유 리소스 (상태 변경)와 같은 시나리오입니다.
sactiw

답변:


99

그들은 완전히 다릅니다. 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*객체를 사용하면 모든 방법이 "원자"임을 보장합니다.

따라서 AtomicIntegerand 를 사용 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컴파일러에 대한 힌트 역할을하여 최적화에 좀 더주의를 기울입니다.


84
-1 : 예제를 제공하지만 실제로 휘발성과 Atomicxxxx의 차이점을 설명하지는 않습니다.
Jason S

70
문제는 아닙니다 volatile. 문제는 volatile booleanvs 에 관한 것 AtomicBoolean입니다.
고인돌

26
-1 : boolean에 대한 질문은 다른 데이터 유형과 비교할 때 고유 한 사례이며 직접 설명해야합니다.
John Haager

8
@ sgp15 Java 5
Man of One Way

6
부울 값을 많은 스레드가 읽지 만 하나의 스레드 만 쓰면 volatile boolean충분합니다. 작가가 많을 경우가 필요할 수 있습니다 AtomicBoolean.
StvnBrkdll

263

해당 필드가 소유자 스레드에 의해서만 업데이트되고 값이 다른 스레드에서만 읽 히면 휘발성 필드를 사용합니다. 관찰자가 많지만 게시자가 하나 인 게시 / 구독 시나리오라고 생각할 수 있습니다. 그러나 해당 관찰자가 필드 값을 기반으로 일부 논리를 수행 한 다음 새 값을 되돌려 야하는 경우 Atomic * vars 또는 locks 또는 동기화 된 블록을 사용하여 가장 적합합니다. 많은 동시 시나리오에서 값을 가져오고 다른 값과 비교하고 필요한 경우 업데이트하므로 Atomic * 클래스에 compareAndSet 및 getAndSet 메소드가 존재합니다.

java.util.concurrent.atomic 패키지 의 JavaDocs에서 Atomic 클래스 목록과 작동 방식에 대한 훌륭한 설명을 확인하십시오 (잠금이 없음을 알게되어 잠금 또는 동기화 된 블록에 비해 유리합니다).


1
@ksl @teto는 하나의 스레드 만 booleanvar를 수정하면 을 선택해야한다고 설명하고 싶습니다 volatile boolean.
znlyj

2
훌륭한 요약.
Ravindra babu

56

당신은 할 수 없어 compareAndSet, getAndSet휘발성 부울와 원자 작업으로 (물론하지 않는 한 당신은 그것을 동기화).


6
이것은 사실이지만 이것이 부울에 대한 매우 드문 요구 사항이 아닙니까?
Robin

1
@Robin은 초기화 메소드의 지연 호출을 제어하는 ​​데 사용하는 것에 대해 생각합니다.
Ustaman Sangat

실제로 이것이 주요 사용 사례 중 하나라고 생각합니다.
fool4jesus

42

AtomicBooleansynchronized블록 을 사용할 필요없이 원자 적으로 복합 연산을 수행하는 메소드가 있습니다 . 반면 volatile booleansynchronized블록 내에서 복합 작업을 수행하는 경우에만 복합 작업을 수행 할 수 있습니다 .

읽기 / 쓰기의 메모리 효과 는 각각 및 방법 과 volatile boolean동일하다 .getsetAtomicBoolean

예를 들어,이 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).


14

volatile키워드는 해당 변수를 공유하는 스레드 간의 관계가 발생하기 전에 보장합니다. 부울 변수에 액세스하는 동안 2 개 이상의 스레드가 서로 인터럽트하지 않는다는 보장은 없습니다.


14
부울 (기본 유형에서와 같이) 액세스는 Java에서 원자 적입니다. 읽기와 과제. 따라서 다른 스레드는 부울 연산을 "중단"하지 않습니다.
Maciej Biłas

1
죄송하지만이 질문에 어떻게 대답합니까? Atomic*클래스는 랩 volatile필드.
그레이

휘발성을 설정하는 주요 요인은 CPU가 캐시하지 않습니까? 읽은 값이 실제로 가장 최근에 설정된 값인지 확인하기 위해
jocull

8

휘발성 부울 대 원자 부울

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 * 클래스를 사용하여 휘발성 필드를 감싸는 것이 객체 관점에서 중요한 공유 리소스를 캡슐화하는 좋은 방법이라는 점에 유의해야합니다. 이것은 개발자가 필드에 문제를 일으킬 가능성이 공유되지 않는다고 가정 할 때 필드를 처리 할 수 ​​없다는 것을 의미합니다. 또는 경쟁 조건을 도입하는 다른 코드.


5

클래스 레벨 변수에 액세스하는 스레드가 여러 개인 경우 각 스레드는 스레드 로컬 캐시에 해당 변수의 사본을 유지할 수 있습니다.

변수를 휘발성으로 만들면 스레드가 스레드 로컬 캐시에 변수 사본을 유지하지 못하게됩니다.

원자 변수는 다르며 값을 원자 적으로 수정할 수 있습니다.


4

부울 프리미티브 유형은 쓰기 및 읽기 작업에 원자 적이며, 휘발성으로 인해 발생하는 원칙을 보장합니다. 따라서 간단한 get () 및 set ()이 필요한 경우 AtomicBoolean이 필요하지 않습니다.

반면에 변수 값을 설정하기 전에 몇 가지 검사를 구현해야하는 경우 (예 : "true 인 경우 false로 설정")이 작업을 원자 적으로 수행해야합니다.이 경우 compareAndSet 및 기타 메소드를 사용하십시오. AtomicBoolean, volatile boolean으로이 논리를 구현하려고하면 값이 get과 set 사이에서 변경되지 않았는지 확인하기 위해 동기화가 필요합니다.


3

IDIOM을 기억하십시오-

READ-MODIFY- WRITE 휘발성으로 달성 할 수없는 쓰기


2
짧고 바삭 바삭하고 요점까지. volatile소유자 스레드가 필드 값을 업데이트 할 수 있고 다른 스레드 만 읽을 수있는 경우에만 작동합니다.
Chaklader Asfak Arefe

3

부울을 수정하는 스레드가 하나만있는 경우 휘발성 부울을 사용할 수 있습니다 (일반적으로 stop스레드의 메인 루프에서 확인 된 변수 를 정의하기 위해 수행 ).

그러나 부울을 수정하는 스레드가 여러 개인 경우을 사용해야합니다 AtomicBoolean. 그렇지 않으면 다음 코드는 안전하지 않습니다.

boolean r = !myVolatileBoolean;

이 작업은 두 단계로 수행됩니다.

  1. 부울 값을 읽습니다.
  2. 부울 값이 기록됩니다.

다른 스레드가 #1와 사이의 값을 수정하면 2#잘못된 결과가 발생할 수 있습니다. AtomicBoolean방법은 단계적 으로 수행 #1하여 #2원자 적 으로이 문제를 피합니다 .


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.