본문 바로가기
JAVA

Java - Atomic변수

by 봄석 2019. 9. 2.

Java - Atomic변수

Atomic변수란

atomic변수는 원자성을 보장하는 변수입니다 . 

멀티쓰레드 환경에서 동기화 문제를 synchronized 키워드를 사용하여 , 락을걸곤하는데 

이런 키워드 없이 동기화문제를 해결하기 위해 고안된 방법입니다.

(일반적으로 동기화문제는 synchronzied, Atomic, volatile 세가지 키워드로 해결합니다)

 

synchronized는 특정  Thead가 해당 블럭 전체를 lock을 하기떄문에 

다른 Thread는 아무런 작업을 하지 못하고 기다리는 상황이 될수 있기때문에 , 낭비가 심합니다.

그래서 NonBlocking하면서 동기화 문제를 해결하기 위한 방법이 Atomic입니다.

 

Atomic의 동작 핵심원리는 바로 CAS알고리즘입니다(Compared and Swap)

 

 

 

CAS( Compared And Swap)알고리즘

1. cas알고리즘
2. cpu캐시메모리

멀티쓰레드환경, 멀티코어 환경에서 각 CPU는 메인 메모리에서 변수값을 참조하는ㄹ게 아닌, 

각 CPU의 캐시 영역에서 메모리를 참조하게 됩니다. (그림 2 참조)

이떄, 메인메모리에 저장된 값과 CPU캐시에 저장된 값이 다른 경우가 있는데 (가시성문제라합니다)

이럴때 사용되는것이 CAS 알고리즘입니다. 현재 쓰레드에 저장된 값메인메모리에 저장된 값을 비교하여 

일치하는경우 새로운 값으로 교체되고 , 일치하지않는다면 실패하고 재시도를 합니다.

이런방법으로 처리하면 ,CPU캐시에 잘못된 값을 참조하는 가시성문제를 해결할 수있습니다.

 

참고로 synchronized 의 경우 synchronized 진입전 메인메모리와 CPU 캐시메모리 값을 동기화 하여 문제가 없도록 처리합니다.

 

 

Atomic변수 예 보기

public class AtomicInteger extends Number implements java.io.Serializable {

	private volatile int value; 
        
        public final int incrementAndGet() { 
	    int current; 
            int next;
            do { 
	        current = get(); 
                next = current + 1; 
            } while (!compareAndSet(current, next));
            return next; 
        } 
        
        public final boolean compareAndSet(int expect, int update) {
        	return unsafe.compareAndSwapInt(this, valueOffset, expect, update); 
        }	
            
}

 

위는 AtomicInteger클래스의 내부입니다.

incrementAndGet()메소드 내부에서 CAS 알고리즘 로직을 구현하고 있습니다.

comparedAndSet()를 호출하고, 그결과값이 성공일때까지 while을 통하여 무한루프롤 돌게됩니다.

comparedAndSet()내부에서는 comparedAndWapInt()를 호출하여 메모리에 저장되어진 값과 현재 CPU에 캐시된 

expect 값을 비교하여 동일한 경우만 변경하는 update쓰기를 수행합니다.

 

여기서 눈여겨 볼 접은 volatile int value; 입니다.

volatile 변수는 가시성 문제를 해결하기 위하여 사용됩니다 .

volatile키워드가 붙어있는 객체는 CPU캐시가 아닌 메모리에서 값을 참조합니다.

그러면 ? 굳이 volatile을 사용하여 메모리에서 직접 값을 참조하는데 CAS알고리즘적용이 필요한가요 ??

네 .필요합니다 .

volatile 키워드는 오직 한개의 쓰레드에서 쓰기작업을할때, 그리고 다른 쓰레드는 읽기작업만을 할떄 안정성을 보장합니다.

하지만 AtomicInteger는 여러 쓰레드에서 읽기/쓰기작업을 병행합니다.

그래서 CAS 알고리즘을 사용하여 2중 안전을 기하는 방법을 사용합니다.

'JAVA' 카테고리의 다른 글

Lombok 알아보기  (4) 2019.09.15
boilerplate  (2) 2019.09.15
Java - Garbage Collection  (0) 2019.09.02
Java - JVM  (0) 2019.09.02
Java - 메모리관리 ( 스택& 힙) [펌]  (0) 2019.09.01

댓글