태그
#JAVA
#동시성
2024년 2월 5일 18:25

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
클래스는 get
및 set
메서드를 통해 참조 값을 읽고 설정할 수 있습니다. 또한 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
}
}
get()
- 객체에 저장된 값을 반환합니다.
set(newValue)
- 객체에 새로운 값을 설정합니다.
getAndSet(newValue)
- 객체에 새로운 값을 설정하고 이전 값을 반환합니다.
compareAndSet(expect, update)
- 객체의 현재 값이
expect
와 일치하는 경우에만 값을update
로 변경합니다. 변경이 성공하면true
를 반환하고, 실패하면false
를 반환합니다.
- 객체의 현재 값이
weakCompareAndSet(expect, update)
compareAndSet
과 동일한 기능을 수행하지만, 약한(weak) 일관성(consistency) 모드로 동작합니다. 약한 일관성 모드에서는 다른 스레드가 동시에 값을 변경할 때 변경이 성공하더라도 다른 스레드에서 변경된 값을 즉시 볼 수 없을 수 있습니다.
lazySet(newValue)
set
과 동일한 기능을 수행하지만, 약한 일관성 모드로 동작합니다.lazySet
을 사용하여 값을 변경하는 경우, 변경된 값을 다른 스레드에서 즉시 볼 수 없을 수 있습니다.
getAndUpdate(function)
- 객체의 현재 값을 사용하여 주어진
function
을 적용하고, 새로운 값을 반환합니다. 이 동작은 원자적으로 이루어집니다.
- 객체의 현재 값을 사용하여 주어진
updateAndGet(function)
getAndUpdate
과 동일한 기능을 수행하지만, 새로운 값을 반환하기 전에function
을 적용합니다.
참고 사이트