๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
develop_kr/java

๐Ÿ”’ Java AtomicReference: ์•ˆ์ „ํ•œ ๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ

by JSsunday 2025. 7. 15.
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 ์••๋ฐ•

๐Ÿ” ๋ฒ ์ŠคํŠธ ํ”„๋ž™ํ‹ฐ์Šค

  1. ๋ถˆ๋ณ€ ๊ฐ์ฒด ์‚ฌ์šฉ: ์ƒํƒœ ๋ณ€๊ฒฝ ์‹œ ์ƒˆ ๊ฐ์ฒด ์ƒ์„ฑ
  2. CAS ๋ฃจํ”„ ์ตœ์ ํ™”: ๋ฌดํ•œ ๋ฃจํ”„ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•œ ๋ฐฑ์˜คํ”„ ์ „๋žต
  3. ์ ์ ˆํ•œ ์‚ฌ์šฉ: ๋‹จ์ˆœํ•œ ์ฐธ์กฐ ์—…๋ฐ์ดํŠธ์—๋งŒ ์‚ฌ์šฉ
  4. ์„ฑ๋Šฅ ํ…Œ์ŠคํŠธ: ์‹ค์ œ ํ™˜๊ฒฝ์—์„œ ์„ฑ๋Šฅ ๊ฒ€์ฆ
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

๋Œ“๊ธ€