Java 잠금없는 동기화 처리 구현 Atomic 클래스
Atomic 클래스
java.util.concurrent.atomic 패키지에서는, 값의 대입/조회 처리를 하드웨어 레벨에서 원자적(Atomic)으로 실행하는 수단을 제공한다.
AtomicBooleanAtomicIntegerAtomicIntegerArrayAtomicLongAtomicLongArray
이러한 클래스를 이용하는 것으로, synchronized 한정자, ReentrantLock 클래스와 같이 락을 사용할 필요 없이, 처리를 동기화 시키는 것이 가능하게 된다.
각 클래스에서 사용할 수 있는 처리에는 다음과 같은 것이 있다.
Atomic 클래스의 주요 메소드
| 메서드 | 개요 | AtomicBoolean 사용 가능 여부 |
|---|---|---|
get() |
현재 값 조회 | O |
getAndSet(newValue) |
현재의 값을 조회오고, 지정된 값을 설정 | O |
set(newValue) |
지정된 값 설정 | O |
getAndAdd(delta) |
지정된 값을 추가(조작 전의 값을 조회) | X |
addAndGet(delta) |
지정된 값을 추가(조작 후의 값을 조회) | X |
getAndDecrement() |
현재의 값을 1 감소(조작 전의 값을 조회) | X |
decrementAndGet() |
현재의 값을 1 감소(조작 후의 값을 조회) | X |
getAndIncrement() |
현재의 값을 1 인크리먼트(조작 전의 값을 조회) | X |
incrementAndGet() |
현재의 값을 1 인크리먼트(조작 후의 값을 조회) | X |
사용 예시
다음은 synchronized 한정자 사용한 예제(increment 메서드)을 AtomicInteger 클래스에서 다시 작성한 것이다. 표준 “i++” 연산은 원자적이지는 않지만 AtomicInteger#getAndIncrement 메서드는 원자적이므로, 값의 조회으로부터 증분, 다시 대입하는 과정에 다른 thread가 인터럽트 하지 않는다.
AtomicSample.java
package com.devkuma.basic.atomic;
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicSample {
private AtomicInteger count = new AtomicInteger();
public static void main(String[] args) {
AtomicSample as = new AtomicSample();
as.execute();
}
public void execute() {
final int THREAD_MAX = 300000;
Thread[] ts = new Thread[THREAD_MAX];
for (int i = 0; i < THREAD_MAX; i++) {
ts[i] = new Thread(new MyThread(this));
ts[i].start();
}
for (int i = 0; i < THREAD_MAX; i++) {
try {
ts[i].join();
} catch (InterruptedException e) {
System.out.println(e);
}
}
System.out.println(count);
}
public void increment() {
count.getAndIncrement();
}
private static class MyThread implements Runnable {
private AtomicSample _counter;
public MyThread(AtomicSample counter) {
this._counter = counter;
}
@Override
public void run() {
_counter.increment();
}
}
}
실행 결과:
300000