멀티쓰레드에서 Thread-Safe 방법

· ☕ 2 min read · 👀... views

1. 멀티 쓰레드(Multi Thread)란?

1-1) 정의

  • 하나의 프로세스를 다수의 실행 단위로 구분하여 자원을 공유하고, 자원의 생성과 관리의 중복성으 최소화하여 수행능력을 향상시키는 것
  • 하나의 프로그램에 동시에 여러개의 일을 수행할 수 있도록 해주는 것

1-2) 멀티 프로세스와의 차이점

  • 멀티 프로세스 : [데이터, 힙, 스택] 영역 모두 비공유
  • 멀티 쓰레드 : [데이터, 힙, 스택] 영역 중 스택만 비공유

2. 쓰레드 세이프 방법

  • 쓰레드를 사용하는 환경에서 성능을 높이기 위해서 멀티 쓰레드를 사용하지만, 힙과 데이터영역은 공유하기 때문에 쓰레드 간에 safe 하지 못하게 됩니다.

1) Synchronized

1
2
3
4
private Integer count = 0;
synchronized (count) {
  count++;
}
  • Block-Lock 으로 임계영역(크리티컬 섹션) 을 설정하는 방식으로 Pessimistic Lock (비관적락) 방식으로 볼 수 있습니다. 문제가 발생하지 않더라도 무조건 쓰레드 차단이 일어나기 때문에 비용이 비쌉니다.
  • 또한, 이전 락 방법 포스팅에서 봤듯이 select 가 읽어나는 시점에서 락을 걸기 때문에 추천하는 방법은 아닙니다.

2) Volatile

  • 데이터를 cache 영역이 아닌 Main Memory 영역에 저장하고 읽어오기 때문에 변수 값 불일치 문제를 해결 할 수 있습니다.
1
private volatile int count = 0;
  • 이 방법은 하나의 Thread 가 read&write 를 하고 나머지 Thread 가 read 를 했을 때 적잡한 방법으로, 다수의 Thread 가 write 하는 상황에서는 적잡하지 않습니다.

3) ReentrankLock

  • synchronized 와 비슷하지만 시작점과 끝점을 수동적으로 설정이 가능한 동기화입니다.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
private final ReentrantLock locker = new ReentrantLock();
public void someMethod() {
    locker.lock();
    try {
        //something
    } catch (Exception e) {
        //some error handle
    } finally {
        locker.unlock();
    }
}

4) AtomicInteger

  • 원자적 연산을 보장하기 위해서 사용합니다.
  • CAS(Compare And Swap) 라는 낙관적 락을 통한 원자적 연산을 지원합니다.
1
2
3
4
public AtomicInteger a = new AtomicInteger(1);
public void someMethod() {
    a.updateAndGet(v -> v+2);
}

3. 정리

Share on

snack
WRITTEN BY
snack
Web Programmer


What's on this Page