목차

1. AtomicReference란?

들어가기

AtomickReference 객체란?

2. AtomicReference 사용법

생성자

함수

태그

#JAVA

#동시성

[Java] AtomicReference에 대하여

2024년 2월 5일 18:25

60-thumbnail-image

1. AtomicReference란?

들어가기

public class Counter {
	int counter;

	public void increment() {
		counter++;
	}
}

위 코드는 단일 스레드 환경의 경우 완벽하게 동작합니다. 하지만 둘 이상의 스레드를 허용하면 위 코드는 일관성 없는 결과가 나타나게 됩니다.

이는 간단한 증감연산자이지만 여러 스레드가 동시에 값을 가져오고 업데이트하려고 하면 업데이트가 손실될 수 있습니다.

public class SafeCounterWithLock {
	private int counter;

	public synchronized void increment() {
		counter++;
	}
}

위의 문제를 방지할 수 있는 방법이 있습니다. 바로 synchronized를 사용하는 것 인데요. synchronized 키워드는 한 번에 하나의 스레드만 메소드에 들어갈 수 있도록 보장합니다.

이러한 키워드를 이용해 문제를 해결할 수 있지만 성능은 큰 타격을 입습니다.

여러 스레드가 lock을 획득하려고 시도하면 그 중 하나의 스레드만 lock을 가져갈 수 있고 나머지 스레드는 차단되거나 일시 중단되어버립니다.

스레드를 일시 중지했다가 다시 시작하는 프로세스는 비용이 많이 들고 시스템의 전반적인 효율성에 영향을 미칩니다.

AtomicReference는 synchronized의 단점을 해결할 수 있습니다.

AtomickReference 객체란?

Java에서 AtomicReference는 원자적(atomic)으로 참조(reference) 변수를 조작할 수 있는 클래스입니다. 원자적이라는 의미는 여러 스레드가 동시에 AtomicReference 객체를 조작하더라도 안전하게 동작한다는 것을 의미합니다.

AtomicReference는 일반적으로 공유되는 변수나 객체를 여러 스레드에서 안전하게 읽고 쓰기 위해 사용됩니다. 예를 들어, 여러 스레드가 동시에 같은 객체를 수정하거나 교체해야 할 때 AtomicReference를 사용하여 동기화된 방식으로 이를 수행할 수 있습니다.

AtomicReference 클래스는 getset 메서드를 통해 참조 값을 읽고 설정할 수 있습니다. 또한 compareAndSet 메서드를 사용하여 현재 값과 예상 값이 일치할 때에만 값을 변경할 수 있습니다. 이를 통해 원자적인 조작을 보장하면서 스레드 간의 경쟁 조건(race condition)을 방지할 수 있습니다.

2. AtomicReference 사용법

생성자

AtomicReference<String> atomic = new AtomicReference<>();
AtomicReference<String> atomic2 = new AtomicReference<>("atomic");

생성자에 초기값을 전달할 수 있으며, 입력하지 않으면 객체는 null로 초기화됩니다.

함수

import java.util.concurrent.atomic.AtomicReference;

public class AtomicReferenceExample {
	public static void main(String[] args) {
		AtomicReference<String> atomic = new AtomicReference<>("atomic");

		System.out.println("get: " + atomic.get()); // get: atomic

		atomic.set("new atomic");
		System.out.println("set: " + atomic.get()); // set: new atomic

		String getAtomic = atomic.getAndSet("atomic");
		System.out.println("getAndSet(Before): " + getAtomic); // getAndSet(Before): new atomic
		System.out.println("getAndSet(After): " + atomic.get()); // getAndSet(After): atomic

		boolean compare = atomic.compareAndSet("atomic", "new atomic");
		System.out.println("compareAndSet(IsCompare): " + compare); // compareAndSet(IsCompare): true
		System.out.println("compareAndSet(result): " + atomic.get()); // compareAndSet(result): new atomic

		boolean compare2 = atomic.compareAndSet("atomic", "compare atomic");
		System.out.println("compareAndSet(IsCompare): " + compare2); // compareAndSet(IsCompare): false
		System.out.println("compareAndSet(result): " + atomic.get()); // compareandSet(result): new atomic
	}
}
  1. get()
    • 객체에 저장된 값을 반환합니다.
  2. set(newValue)
    • 객체에 새로운 값을 설정합니다.
  3. getAndSet(newValue)
    • 객체에 새로운 값을 설정하고 이전 값을 반환합니다.
  4. compareAndSet(expect, update)
    • 객체의 현재 값이 expect와 일치하는 경우에만 값을 update로 변경합니다. 변경이 성공하면 true를 반환하고, 실패하면 false를 반환합니다.
  5. weakCompareAndSet(expect, update)
    • compareAndSet과 동일한 기능을 수행하지만, 약한(weak) 일관성(consistency) 모드로 동작합니다. 약한 일관성 모드에서는 다른 스레드가 동시에 값을 변경할 때 변경이 성공하더라도 다른 스레드에서 변경된 값을 즉시 볼 수 없을 수 있습니다.
  6. lazySet(newValue)
    • set과 동일한 기능을 수행하지만, 약한 일관성 모드로 동작합니다. lazySet을 사용하여 값을 변경하는 경우, 변경된 값을 다른 스레드에서 즉시 볼 수 없을 수 있습니다.
  7. getAndUpdate(function)
    • 객체의 현재 값을 사용하여 주어진 function을 적용하고, 새로운 값을 반환합니다. 이 동작은 원자적으로 이루어집니다.
  8. updateAndGet(function)
    • getAndUpdate과 동일한 기능을 수행하지만, 새로운 값을 반환하기 전에 function을 적용합니다.

참고 사이트