Java Adv 14 - atomic operation - 3
in Programming Language on Java
AtomicInteger
자바는 앞서 만든 SyncInteger 와 같이 멀티스레드 상황에서 안전하게 증가 연산을 수행할 수 있는 AtomicInteger 라는 클래스를 제공한다. 이름 그대로 원자적인 Integer 라는 뜻이다. 다음과 같이 MyAtomicInteger 클래스를 만들고, 자바가 제공하는 AtomicInteger 를 사용해보자.
new AtomicInteger(0): 초기값을 지정한다. 생략하면0부터 시작한다.incrementAndGet(): 값을 하나 증가하고 증가된 결과를 반환한다.get(): 현재 값을 반환한다.
실행 결과를 보면 AtomicInteger 를 사용하면 MyAtomicInteger 의 결과도 1000인 것을 확인할 수 있다. 1000개의 스레드가 안전하게 증가 연산을 수행한 것이다. AtomicInteger 는 멀티스레드 상황에 안전하고 또 다양한 값 증가, 감소 연산을 제공한다. 특정 값을 증가하거나 감소해야 하는데 여러 스레드가 해당 값을 공유해야 한다면, AtomicInteger 를 사용하면 된다.
성능 테스트
- BasicInteger
- 가장 빠르다.
- CPU 캐시를 적극 사용한다. CPU 캐시의 위력을 알 수 있다.
- 안전한 임계 영역도 없고,
volatile도 사용하지 않기 때문에 멀티스레드 상황에는 사용할 수 없다. - 단일 스레드가 사용하는 경우에 효율적이다.
- VolatileInteger
volatile을 사용해서 CPU 캐시를 사용하지 않고 메인 메모리를 사용한다.- 안전한 임계 영역이 없기 때문에 멀티스레드 상황에는 사용할 수 없다.
- 단일 스레드가 사용하기에는
BasicInteger보다 느리다. 그리고 멀티스레드 상황에도 안전하지 않다.
- SyncInteger
synchronized를 사용한 안전한 임계 영역이 있기 때문에 멀티스레드 상황에도 안전하게 사용할 수 있다.MyAtomicInteger보다 성능이 느리다.
- MyAtomicInteger
- 자바가 제공하는
AtomicInteger를 사용한다. 멀티스레드 상황에 안전하게 사용할 수 있다. - 성능도
synchronized,Lock(ReentrantLock)을 사용하는 경우보다 1.5 ~ 2배 정도 빠르다. SyncInteger처럼 락을 사용하는 경우보다,AtomicInteger가 더 빠른 이유는 무엇일까?i++연산은 원자적인 연산이 아니다.- 따라서 분명히
synchronized,Lock(ReentrantLock)와 같은 락을 통해 안전한 임계 영역을 만들어야 할 것 같다. - 놀랍게도
AtomicInteger가 제공하는incrementAndGet()메서드는 락을 사용하지 않고, 원자적 연산을 만들어낸다.
- 자바가 제공하는
Reference
김영한님의 자바 강의