1. 멀티 쓰레드(Multi Thread)란?
1-1) 정의
- 하나의 프로세스를 다수의 실행 단위로 구분하여 자원을 공유하고, 자원의 생성과 관리의 중복성으 최소화하여 수행능력을 향상시키는 것
- 하나의 프로그램에 동시에 여러개의 일을 수행할 수 있도록 해주는 것
1-2) 멀티 프로세스와의 차이점
- 멀티 프로세스 : [데이터, 힙, 스택] 영역 모두 비공유
- 멀티 쓰레드 : [데이터, 힙, 스택] 영역 중 스택만 비공유
2. 쓰레드 세이프 방법
- 쓰레드를 사용하는 환경에서 성능을 높이기 위해서 멀티 쓰레드를 사용하지만, 힙과 데이터영역은 공유하기 때문에 쓰레드 간에 safe 하지 못하게 됩니다.
1) Synchronized
private Integer count = 0;
synchronized (count) {
count++;
}
- Block-Lock 으로 임계영역(크리티컬 섹션) 을 설정하는 방식으로 Pessimistic Lock (비관적락) 방식으로 볼 수 있습니다. 문제가 발생하지 않더라도 무조건 쓰레드 차단이 일어나기 때문에 비용이 비쌉니다.
- 또한, 이전 락 방법 포스팅에서 봤듯이 select 가 읽어나는 시점에서 락을 걸기 때문에 추천하는 방법은 아닙니다.
2) Volatile
- 데이터를 cache 영역이 아닌 Main Memory 영역에 저장하고 읽어오기 때문에 변수 값 불일치 문제를 해결 할 수 있습니다.
private volatile int count = 0;
- 이 방법은 하나의 Thread 가 read&write 를 하고 나머지 Thread 가 read 를 했을 때 적잡한 방법으로, 다수의 Thread 가 write 하는 상황에서는 적잡하지 않습니다.
3) ReentrankLock
- synchronized 와 비슷하지만 시작점과 끝점을 수동적으로 설정이 가능한 동기화입니다.
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) 라는 낙관적 락을 통한 원자적 연산을 지원합니다.
public AtomicInteger a = new AtomicInteger(1);
public void someMethod() {
a.updateAndGet(v -> v+2);
}
3. 정리
- 멀티 쓰레드 환경에서 쓰레드 세이프한 방법을 알아봤는데요. 검색해보니 방법은 대략적으로 저렇게 4가지 방법이 있는 것 같습니다. 락이라는 표현도 나오기 때문에 어떻게 보면 이전에 포스팅했던 JPA 락에 대한 것들이 생각나는 정리였네요.
- 해당 내용은 하나의 서버에서 멀티 쓰레딩을 했을 때에 대한 정리이므로 멀티 서버에서 멀티 쓰레딩이라면 또 다른 점을 고려해야 할 것 같습니다. (멀티 서버간 공유는 하고 있지 않을 것 같아요.).
지금 드는 생각으로는 멀티 서버를 쓰레드 개념처럼 사용할 수 있게 게이트웨이 서버같은 것을 두거나 하는 방법이 있을 수도 있을 것 같은데.. 생각만 입니다.
- 참고