[Java] AtomicLong

gyeol·2025년 10월 2일
0

자바

목록 보기
20/23
post-thumbnail

Atomic 클래스란?

자바에서는 멀티스레드 환경에서 하나의 변수를 여러 스레드가 동시에 읽고 쓰게되면 race condition이 발생한다. 이를 해결하려면 synchronized 같은 락을 걸어야 하지만, 락은 성능에 영향을 줄 수 있기에 Atomic 클래스를 사용한다.

  • AtomicInteger
  • AtomicLong
  • AtomicBoolean
  • AtomicReference

이들은 CAS(Compare-And-Set) 방식으로 락 없이 원자적 연산을 보장한다.

AtomicLong

  • 내부에 long 값을 하나 보관
  • 멀티스레드 환경에서 이 값에 대해 원자적 연산 제공
  • volatile과 메모리 가시성을 보장 -> 다른 스레드에서 즉시 반영된 값 확인 가능
  • 락 없이도 안전하게 사용 가능
AtomicLong counter = new AtomicLong(0);

// 값 읽기
long value = counter.get();

// 값 설정
counter.set(10);

// 원자적 증가
counter.incrementAndGet();  // 1 증가 후 결과 반환
counter.getAndIncrement();  // 현재 값 반환 후 1 증가

객체 생성

  • AtomicLong() : 초기값이 0인 AtomicLong을 생성
  • AtomicLong(longVal) : 인자의 값으로 초기화된 AtomicLong 생성

주요 메서드

메서드설명
get()현재 값 읽기
set(long newValue)새로운 값으로 설정
getAndIncrement()현재 값 반환 후 +1 (후증가)
incrementAndGet()+1 후 증가된 값 반환 (전증가)
getAndAdd(long delta) / addAndGet(long delta)delta만큼 더하기
compareAndSet(expect, update)현재 값이 expect일 때만 update로 교체

예시 (CAS 활용)

compareAndSet을 이용하면 특정 로직을 최초 한 번만 실행하도록 할 수 있다.

import java.util.concurrent.atomic.AtomicLong;

class Once {
    private AtomicLong done = new AtomicLong(0);

    public void runOnce(Runnable action) {
        if (done.compareAndSet(0, 1)) {
            action.run();
        }
    }
}

public class Test {
    public static void main(String[] args) {
        Once once = new Once();
        once.runOnce(() -> System.out.println("Hello World!"));
        once.runOnce(() -> System.out.println("두 번째 실행은 무시됨"));
    }
}

예시

  • Task 클래스: name, priority(정수, 클수록 우선순위 높음).
  • Scheduler 클래스
    • addTask(Task task)
    • getNextTask() → 가장 높은 우선순위 반환 (동점이면 먼저 들어온 순서)
public class test2 {
    public static void main(String[] args) {
        Scheduler scheduler = new Scheduler();
        scheduler.addTask(new Task("A", 1));
        scheduler.addTask(new Task("B", 3));
        scheduler.addTask(new Task("C",1));

        System.out.println(scheduler.getNextTask());
        System.out.println(scheduler.getNextTask());

    }
}

class Task{
    String name;
    int priority;
    long seq;

    public Task(String name, int priority){
        this.name = name;
        this.priority = priority;
    }

    @Override
    public String toString(){
        return name;
    }
}

class Scheduler{
    private PriorityQueue<Task> queue;
    private AtomicLong sequence = new AtomicLong(0);

    public Scheduler(){
        queue = new PriorityQueue<>((t1, t2) -> {
            if(t1.priority != t2.priority){ // 우선순위가 같지 않다면 
                return Integer.compare(t2.priority, t1.priority);
            } else { // 우선순위가 같다면 들어온 순서대로
                return Long.compare(t1.seq, t2.seq);
            }
        });
    }

    public void addTask(Task task){
        task.seq = sequence.getAndIncrement();
        queue.offer(task);
    }

    public String getNextTask(){
        Task task = queue.poll();
        return task == null ? null : task.name;
    }
}
profile
공부 기록 공간 '◡'

0개의 댓글