728x90
๋ฐ์ํ
๐ AtomicReference์ ํ์ ๋ฐฐ๊ฒฝ
๋ฉํฐ์ค๋ ๋ ํ๊ฒฝ์์ ๊ฐ์ฒด ์ฐธ์กฐ๋ฅผ ์์ ํ๊ฒ ๋ค๋ฃจ๋ ๊ฒ์ Java ๊ฐ๋ฐ์๋ค์๊ฒ ํญ์ ๋์ ์ด์์ต๋๋ค. ์ ํต์ ์ธ synchronized ํค์๋๋ ์ฑ๋ฅ ์ค๋ฒํค๋๊ฐ ํฌ๊ณ , ๋ฐ๋๋ฝ ์ํ์ฑ์ด ์กด์ฌํ์ต๋๋ค.
Java 5์์ ๋์ ๋ java.util.concurrent.atomic ํจํค์ง๋ ์ด๋ฌํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ๋ฑ์ฅํ์ต๋๋ค. AtomicReference๋ ๊ฐ์ฒด ์ฐธ์กฐ์ ๋ํ ์์์ (atomic) ์ฐ์ฐ์ ์ ๊ณตํ์ฌ, ๋ฝ ์์ด๋ ์ค๋ ๋ ์์ ์ฑ์ ๋ณด์ฅํฉ๋๋ค.
๐ฏ AtomicReference๊ฐ ํ์ํ ์ํฉ
๐ ์ฃผ์ ์ฌ์ฉ ์๋๋ฆฌ์ค
- ๋ฉํฐ์ค๋ ๋ ํ๊ฒฝ์์ ๊ฐ์ฒด ์ฐธ์กฐ ์ ๋ฐ์ดํธ
- Compare-and-Swap (CAS) ์ฐ์ฐ์ด ํ์ํ ๊ฒฝ์ฐ
- ๋ฝํ๋ฆฌ(Lock-free) ์๊ณ ๋ฆฌ์ฆ ๊ตฌํ
- ์บ์ ์์คํ ์์ ์์ ํ ์ฐธ์กฐ ๊ด๋ฆฌ
- ์ํ ๋จธ์ ์ ์ํ ์ ํ ๊ด๋ฆฌ
๐ง AtomicReference ํต์ฌ ๋ฉ์๋
๋ฉ์๋ ์ค๋ช
get() | ํ์ฌ ๊ฐ์ ๋ฐํ |
set(V newValue) | ๊ฐ์ ์ค์ |
compareAndSet(V expected, V update) | ๊ธฐ๋๊ฐ๊ณผ ๊ฐ์ผ๋ฉด ์ ๋ฐ์ดํธ |
getAndSet(V newValue) | ์ด์ ๊ฐ์ ๋ฐํํ๊ณ ์ ๊ฐ์ผ๋ก ์ค์ |
๐ก ์ค์ ์์ ์ฝ๋
์์ 1: ์ค๋ ๋ ์์ ํ ์นด์ดํฐ ๊ตฌํ
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class AtomicCounterExample {
private static class Counter {
private final int value;
public Counter(int value) {
this.value = value;
}
public Counter increment() {
return new Counter(value + 1);
}
public int getValue() {
return value;
}
}
private final AtomicReference<Counter> counter = new AtomicReference<>(new Counter(0));
public void increment() {
Counter current, updated;
do {
current = counter.get();
updated = current.increment();
} while (!counter.compareAndSet(current, updated));
}
public int getValue() {
return counter.get().getValue();
}
public static void main(String[] args) throws InterruptedException {
AtomicCounterExample example = new AtomicCounterExample();
ExecutorService executor = Executors.newFixedThreadPool(10);
// 1000๊ฐ์ ์ฆ๊ฐ ์์
์ ๋์์ ์คํ
for (int i = 0; i < 1000; i++) {
executor.submit(example::increment);
}
executor.shutdown();
executor.awaitTermination(1, TimeUnit.SECONDS);
System.out.println("์ต์ข
์นด์ดํฐ ๊ฐ: " + example.getValue()); // 1000
}
}
์์ 2: ๋ฉํฐ์ค๋ ๋ ํ๊ฒฝ์์์ ์บ์ ์์คํ
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
public class AtomicCacheExample {
private static class CacheEntry<T> {
private final T value;
private final long timestamp;
private final long ttl; // Time To Live (milliseconds)
public CacheEntry(T value, long ttl) {
this.value = value;
this.timestamp = System.currentTimeMillis();
this.ttl = ttl;
}
public boolean isExpired() {
return System.currentTimeMillis() - timestamp > ttl;
}
public T getValue() {
return value;
}
}
private final AtomicReference<CacheEntry<String>> cache = new AtomicReference<>();
public String getValue(Supplier<String> dataLoader) {
CacheEntry<String> current = cache.get();
// ์บ์๊ฐ ๋น์ด์๊ฑฐ๋ ๋ง๋ฃ๋ ๊ฒฝ์ฐ
if (current == null || current.isExpired()) {
String newValue = dataLoader.get();
CacheEntry<String> newEntry = new CacheEntry<>(newValue, 5000); // 5์ด TTL
// CAS๋ฅผ ์ฌ์ฉํ์ฌ ์์์ ์ผ๋ก ์
๋ฐ์ดํธ
if (cache.compareAndSet(current, newEntry)) {
return newValue;
} else {
// ๋ค๋ฅธ ์ค๋ ๋๊ฐ ์ด๋ฏธ ์
๋ฐ์ดํธํ ๊ฒฝ์ฐ, ์
๋ฐ์ดํธ๋ ๊ฐ์ ๋ฐํ
return cache.get().getValue();
}
}
return current.getValue();
}
public static void main(String[] args) throws InterruptedException {
AtomicCacheExample cache = new AtomicCacheExample();
// ์ฌ๋ฌ ์ค๋ ๋๊ฐ ๋์์ ์บ์์ ์ ๊ทผ
Runnable task = () -> {
String result = cache.getValue(() -> {
System.out.println("๋ฐ์ดํฐ ๋ก๋ฉ ์ค... (Thread: " + Thread.currentThread().getName() + ")");
try {
Thread.sleep(100); // ๋ฐ์ดํฐ ๋ก๋ฉ ์๋ฎฌ๋ ์ด์
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return "Cached Data at " + System.currentTimeMillis();
});
System.out.println("๊ฒฐ๊ณผ: " + result + " (Thread: " + Thread.currentThread().getName() + ")");
};
// ๋์์ 5๊ฐ ์ค๋ ๋ ์คํ
for (int i = 0; i < 5; i++) {
new Thread(task).start();
}
Thread.sleep(1000);
}
}
์์ 3: ์ํ ๋จธ์ ๊ตฌํ
import java.util.concurrent.atomic.AtomicReference;
public class StateMachineExample {
public enum State {
IDLE, RUNNING, PAUSED, STOPPED
}
private final AtomicReference<State> currentState = new AtomicReference<>(State.IDLE);
public boolean start() {
return currentState.compareAndSet(State.IDLE, State.RUNNING);
}
public boolean pause() {
return currentState.compareAndSet(State.RUNNING, State.PAUSED);
}
public boolean resume() {
return currentState.compareAndSet(State.PAUSED, State.RUNNING);
}
public boolean stop() {
State current = currentState.get();
return (current == State.RUNNING || current == State.PAUSED) &&
currentState.compareAndSet(current, State.STOPPED);
}
public boolean reset() {
return currentState.compareAndSet(State.STOPPED, State.IDLE);
}
public State getState() {
return currentState.get();
}
public static void main(String[] args) {
StateMachineExample machine = new StateMachineExample();
System.out.println("์ด๊ธฐ ์ํ: " + machine.getState());
if (machine.start()) {
System.out.println("์์ ์ฑ๊ณต: " + machine.getState());
}
if (machine.pause()) {
System.out.println("์ผ์์ ์ง ์ฑ๊ณต: " + machine.getState());
}
if (machine.resume()) {
System.out.println("์ฌ๊ฐ ์ฑ๊ณต: " + machine.getState());
}
if (machine.stop()) {
System.out.println("์ ์ง ์ฑ๊ณต: " + machine.getState());
}
if (machine.reset()) {
System.out.println("๋ฆฌ์
์ฑ๊ณต: " + machine.getState());
}
// ์๋ชป๋ ์ํ ์ ํ ์๋
if (!machine.pause()) {
System.out.println("IDLE ์ํ์์ ์ผ์์ ์ง ๋ถ๊ฐ๋ฅ");
}
}
}
โก ์ฑ๋ฅ ๊ณ ๋ ค์ฌํญ
๐ ์ฅ์
- ๋ฝํ๋ฆฌ: ๋ฐ๋๋ฝ ์ํ ์์
- ๋์ ์ฑ๋ฅ: ๊ฒฝํฉ์ด ์ ์ ๋ ๋ฐ์ด๋ ์ฑ๋ฅ
- ์์์ฑ ๋ณด์ฅ: ์ค๋ ๋ ์์ ํ ์ฐ์ฐ
๐ ๋จ์
- ABA ๋ฌธ์ : ๊ฐ์ด A→B→A๋ก ๋ณ๊ฒฝ๋ ๋ ๊ฐ์ง ๋ชปํจ
- ์คํ ๋๊ธฐ: ๊ฒฝํฉ์ด ํด ๋ CPU ์ฌ์ฉ๋ ์ฆ๊ฐ
- ๋ฉ๋ชจ๋ฆฌ ํ ๋น: ๋ถ๋ณ ๊ฐ์ฒด ์ฌ์ฉ ์ GC ์๋ฐ
๐ ๋ฒ ์คํธ ํ๋ํฐ์ค
- ๋ถ๋ณ ๊ฐ์ฒด ์ฌ์ฉ: ์ํ ๋ณ๊ฒฝ ์ ์ ๊ฐ์ฒด ์์ฑ
- CAS ๋ฃจํ ์ต์ ํ: ๋ฌดํ ๋ฃจํ ๋ฐฉ์ง๋ฅผ ์ํ ๋ฐฑ์คํ ์ ๋ต
- ์ ์ ํ ์ฌ์ฉ: ๋จ์ํ ์ฐธ์กฐ ์ ๋ฐ์ดํธ์๋ง ์ฌ์ฉ
- ์ฑ๋ฅ ํ ์คํธ: ์ค์ ํ๊ฒฝ์์ ์ฑ๋ฅ ๊ฒ์ฆ
728x90
๋ฐ์ํ
'develop_kr > java' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
JAVA EE๋? (0) | 2023.01.28 |
---|---|
JDBC, DBCP ๊ทธ๋ฆฌ๊ณ JNDI (0) | 2022.12.09 |
JAVA 8 ํจ์ํ ์ธํฐํ์ด์ค (0) | 2022.11.12 |
์ด๊ฑฐํ(enum) (0) | 2022.10.29 |
JAVA8 STREAM(1) (1) | 2022.10.15 |
๋๊ธ