Java에서 AtomicBoolean을 언제 사용해야합니까?


답변:


244

여러 스레드가 부울을 확인하고 변경해야하는 경우 예를 들면 다음과 같습니다.

if (!initialized) {
   initialize();
   initialized = true;
}

스레드 안전하지 않습니다. 다음을 사용하여 문제를 해결할 수 있습니다 AtomicBoolean.

if (atomicInitialized.compareAndSet(false, true)) {
    initialize();
}

51
실제 예제처럼 보이지는 않습니다. 다른 스레드는 완료되지 않은 true시점 initialize()을 볼 수 있습니다 . 따라서 다른 스레드가 완료를 신경 쓰지 않는 경우에만 작동합니다 initialize().
axtavt

6
@axtavt : initialized하나의 스레드 만 initialize()메소드 를 호출하도록 보장하는 데 사용되는 경우 실제로 유효한 실제 예제라고 생각합니다 . 분명히 initialized그 초기화를 의미하지 않는다 진실되고하는 것은 확실히 때문에,이 경우 완료 어쩌면 약간 다른 용어보다 잘 될 것입니다. 다시, 그것은 그것이 사용되는 것에 달려 있습니다.
ColinD

14
initStarted 및 initCompleted에 대해 2 개의 부울이 필요하며, 첫 번째 스레드가 initStarted를 설정하고 initialise ()를 호출하면 나머지는 initCompleted가 true가 될 때까지 대기합니다.
Martin

3
@Bozho- boolean 필드 를 읽고 쓰는 것이 원자 적 권리입니까?, 이제 volatile 은 boolean 필드의 최신 값을 제공합니다. 따라서 효과적으로 ? volatile boolean와 같지 않습니다 AtomicBoolean.
TheLostMind

2
@Martin : 부울이 사실이 될 때까지 기다리는 직접적인 방법은 없습니다. 추가 메커니즘이 필요합니다. 가장 현명한 방법은 사용하는 것입니다 synchronized당신이 더 이상을 필요로하는 경우에 블록 AtomicBoolean단지를 volatile boolean. ( if(! this.initialized) { synchronized(this) { if(! this.initialized) { initialize(); this.initialized = true; } } }하나의 스레드 만 호출 initialize하고 다른 모든 스레드는 스레드 initialized가 표시 될 때까지 기다립니다 volatile.)
ruakh

52

여기 내가 작성한 참고 사항 ( Brian Goetz book )이 도움이 될 것입니다.

AtomicXXX 수업

  • 비 차단 비교 및 ​​스왑 구현 제공

  • 하드웨어 (Intel의 CMPXCHG 명령)가 제공하는 지원을 활용합니다. 이러한 원자 적 동시성 API를 사용하는 코드를 통해 많은 스레드가 실행중인 경우 객체 레벨 모니터 / 동기화를 사용하는 코드보다 훨씬 확장 성이 뛰어납니다. Java의 동기화 메커니즘으로 인해 코드 대기 상태가되므로 중요한 섹션을 통해 많은 스레드가 실행되는 경우 동기화 메커니즘 자체 (대기, 알림 등)를 관리하는 데 상당한 양의 CPU 시간이 소요됩니다. 새로운 API는 하드웨어 수준 구성 (원자 변수)을 사용하고 스레드 안전을 구현하기 위해 사용 가능한 알고리즘을 대기 및 잠금 상태로 만들기 때문에 동기화를 관리하는 대신 "작업 수행"에 훨씬 많은 CPU 시간이 소비됩니다.

  • 더 나은 처리량을 제공 할뿐만 아니라 교착 상태 및 우선 순위 반전과 같은 작동 문제에 대한 저항력도 향상됩니다.


34

원자 부울을 사용할 수있는 두 가지 주요 이유가 있습니다. 먼저 변경 가능하므로 참조로 전달하고 예를 들어 부울 자체와 관련된 값을 변경할 수 있습니다.

public final class MyThreadSafeClass{

    private AtomicBoolean myBoolean = new AtomicBoolean(false);
    private SomeThreadSafeObject someObject = new SomeThreadSafeObject();

    public boolean doSomething(){
         someObject.doSomeWork(myBoolean);
         return myBoolean.get(); //will return true
    }
}

그리고 someObject 클래스에서

public final class SomeThreadSafeObject{
    public void doSomeWork(AtomicBoolean b){
        b.set(true);
    }
}

더 중요한 것은 스레드가 안전하고 클래스를 유지 관리하는 개발자 에게이 변수가 수정되어 여러 스레드에서 읽힐 것으로 예상 될 수 있음을 나타낼 수 있습니다. AtomicBoolean을 사용하지 않는 경우 사용중인 부울 변수를 휘발성으로 선언하거나 필드의 읽기 및 쓰기 주위에서 동기화하여 부울 변수를 동기화해야합니다.


4
신의 사랑을 위해서, 그것은 단지 물체 자체의 가변성을 보여주기위한 것이었다. 나는 구체적으로 데모 목적으로 그것을 썼다.
John Vint

더 나아가, 그것이 모두 일어나고 있었다면 그렇다면, 그것은 항상 참을 돌려 줄 것입니다
John Vint

그것이 스레드 안전하지 않은지 증명하지 않습니다. 클래스를 스레드로부터 안전하게 만들기 위해 코드 스 니펫을 완료 할 수는 있지만 요점 만 죽입니다.
John Vint

1
휘발성만으로는 충분하지 않다고 생각합니다. 주 메모리에서 동일한 값을 직접 읽고 쓰는 두 개의 스레드가 해당 스레드간에 동기화되지 않는 상황을 생각해보십시오. 동시성 문제가 발생할 수 있습니다.
Shay Tsadok

1
OP의 컨텍스트가 충분하지 않아서 원자 집합 및 작업 확인으로는 충분하지 않을 것입니다. 즉, 상황에 따라 휘발성이 충분하지 않을 수 있습니다.
John Vint


5

패키지 설명 에서 발췌

패키지 java.util.concurrent.atomic 설명 : 단일 변수에서 잠금없는 스레드 안전 프로그래밍을 지원하는 작은 클래스의 툴킷 [...]

이러한 방법의 사양은 구현이 최신 프로세서에서 사용할 수있는 효율적인 기계 수준의 원자 명령어를 사용할 수 있도록합니다. [...]

AtomicBoolean, AtomicInteger, AtomicLong 및 AtomicReference 클래스의 인스턴스는 각각 해당 유형의 단일 변수에 대한 액세스 및 업데이트를 제공합니다. [...]

원자의 접근 및 업데이트에 대한 메모리 효과는 일반적으로 휘발성 물질에 대한 규칙을 따릅니다.

  • get은 휘발성 변수를 읽는 메모리 효과가 있습니다.
  • set은 휘발성 변수를 작성 (할당)하는 메모리 효과가 있습니다.
  • weakCompareAndSet는 원자 적으로 변수를 읽고 조건부로 쓰고 해당 변수에 대한 다른 메모리 작업과 관련하여 정렬되지만 일반적인 비 휘발성 메모리 작업으로 작동합니다.
  • compareAndSet 및 getAndIncrement와 같은 다른 모든 읽기 및 업데이트 작업은 휘발성 변수를 읽고 쓰는 데 메모리 효과가 있습니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.