Java 잠금없는 동기화 처리 구현 Atomic 클래스

Atomic 클래스

java.util.concurrent.atomic 패키지에서는, 값의 대입/조회 처리를 하드웨어 레벨에서 원자적(Atomic)으로 실행하는 수단을 제공한다.

  • AtomicBoolean
  • AtomicInteger
  • AtomicIntegerArray
  • AtomicLong
  • AtomicLongArray

이러한 클래스를 이용하는 것으로, 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



최종 수정 : 2022-09-24