카테고리 없음

[JAVA] 심화

밈98 2025. 1. 23. 20:56

동시성과 병렬성

 

  • 동시성(Concurrency): 여러 작업을 동시에 처리하는 것처럼 보이도록 구현하는 방식으로, 단일 CPU에서 여러 작업이 빠르게 번갈아가며 실행됩니다. ex) 멀티스레드 프로그램.
  • 병렬성(Parallelism): 여러 작업이 실제로 동시에 실행되는 방식으로, 다중 CPU나 다중 코어에서 각각 다른 작업을 동시에 수행합니다. ex) 멀티프로세싱.

 

 

동시성, 병렬성

멀티 스레드

멀티 스레드란 동시성을 달성할 수 있는 하나의 프로그래밍 기법이다.

 

Thread-Safe란?

다수의 스레드가 공유 자원에 접근해도 프로그램이 문제 없이 동작하는 것을 의미한다.

 

 

 

  • Thread Safe 를 지키기 위한 방법은 4가지로 되어있다.
    • Mutual exclusion (상호 배제)
    • Atomic operation (원자 연산)
    • Thread-local storage (쓰레드 지역 저장소)
    • Re-entrancy (재진입성)
public class ThreadSafeExample {
    private int count = 0;

    // synchronized 키워드로 메서드에 락 설정
    public synchronized void increment() {
        count++;
    }

    public synchronized int getCount() {
        return count;
    }

    public static void main(String[] args) {
        ThreadSafeExample example = new ThreadSafeExample();

        Runnable task = () -> {
            for (int i = 0; i < 1000; i++) {
                example.increment();
            }
        };

        Thread thread1 = new Thread(task);
        Thread thread2 = new Thread(task);

        thread1.start();
        thread2.start();

        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Final count: " + example.getCount());
    }
}

increment와 getCount 메서드가 synchronized로 보호되어 여러 스레드가 동시에 접근해도 안전합니다.

 

 

  • 가시성 문제: 한 스레드가 변경한 데이터가 다른 스레드에게 즉시 보이지 않을 때 발생합니다. CPU 캐싱이나 레지스터 최적화 때문에 발생하며, volatile 키워드 또는 동기화 메커니즘으로 해결할 수 있습니다.
  • 원자성 문제: 작업이 중간에 끼어들기 없이 완전히 실행되거나 전혀 실행되지 않는 성질이 보장되지 않을 때 발생합니다. 예를 들어, i++ 같은 연산은 읽기, 증가, 쓰기 세 단계로 이루어져 원자적이지 않습니다.

자바의 동시성 이슈 해결 방법

  1. 동기화(synchronization):
    • synchronized 키워드로 특정 코드 블록이나 메서드에 락을 걸어 한 번에 하나의 스레드만 접근 가능하게 함.
  2. volatile 키워드:
    • 변수의 값을 메인 메모리에 즉시 반영하도록 하여 가시성 문제를 해결.
  3. Lock 클래스:
    • java.util.concurrent.locks 패키지의 ReentrantLock 등을 사용해 세밀한 락 제어 가능.
  4. Atomic 클래스:
    • java.util.concurrent.atomic 패키지에서 제공하는 클래스 (AtomicInteger, AtomicLong)로 원자적 연산 보장.
  5. ExecutorService:
    • 스레드 관리를 위한 스레드 풀을 제공.
  6. Concurrent 컬렉션:
    • ConcurrentHashMap, CopyOnWriteArrayList 등 Thread-Safe 자료구조.

5. volatile 키워드

  • 정의: 변수의 값을 스레드별 캐시가 아닌 메인 메모리에 직접 저장하고 읽게 하여 가시성 문제를 해결.
  • 제약:
    • 원자성을 보장하지 않음. 예를 들어, count++는 volatile만으로 안전하지 않음.
    • 복잡한 연산에는 적합하지 않음.

6. synchronized 키워드

  • 정의: 코드 블록이나 메서드에 락을 걸어 한 번에 하나의 스레드만 해당 코드에 접근 가능하도록 만듦.
  • 사용 예:
    java
    복사편집
    public synchronized void increment() { count++; } public void decrement() { synchronized(this) { count--; } }

7. synchronized의 문제점

  1. 성능 저하:
    • 락을 획득하고 해제하는 과정에서 비용이 발생.
    • 불필요한 락 경쟁으로 인해 성능 문제가 생길 수 있음.
  2. 데드락(Deadlock):
    • 두 스레드가 서로가 가진 락을 기다리며 무한 대기 상태에 빠질 가능성.
  3. 가시성 문제:
    • 잘못된 동기화로 인해 여전히 가시성 문제가 발생할 수 있음.

8. synchronized 구현되어있는 방식

  • 자바의 synchronized는 모니터 락(Monitor Lock) 개념을 사용하며, 객체의 내부 모니터(헤더)를 이용하여 락을 관리합니다.
  • JVM 레벨에서 synchronized는 모니터(MonitorEnter/MonitorExit) 명령어로 컴파일되어 실행됩니다.
  • 최적화를 위해 바이오닉 락(Biased Locking), 경량 락(Lightweight Locking), 중량 락(Heavyweight Locking) 같은 락 업그레이드/다운그레이드 메커니즘을 사용합니다.

9. atomic은 ???

  • 원자적(atomic): 작업이 더 이상 나눠질 수 없는 단위로 실행되어, 작업 도중 다른 스레드가 개입할 수 없음을 의미합니다.
  • 예: 하나의 작업(읽기, 쓰기 등)이 반드시 완료되거나 전혀 실행되지 않는 성질.

10. atomic 타입은??

  • Atomic 타입: java.util.concurrent.atomic 패키지에 속한 클래스로, 원자적 연산을 제공하는 데이터 타입입니다.
  • 주요 클래스:
    • AtomicInteger
    • AtomicLong
    • AtomicReference
    • AtomicBoolea
  • 동시성과 병렬성은 실행 방식의 차이이며, 동시성은 논리적 병렬 처리, 병렬성은 물리적 병렬 처리입니다.
  • Thread-Safe는 여러 스레드 접근에도 데이터가 안전함을 의미합니다.
  • 가시성 문제는 메모리 일관성 문제이고, 원자성 문제는 작업의 중단 불가성을 보장하지 않는 경우를 의미합니다.
  • 자바에서는 volatile, synchronized, Lock, ExecutorService, Atomic 클래스 등을 활용하여 동시성 문제를 해결합니다.