동기화 문제
- 데이터 경쟁 (Race Condition)
- 두 개 이상의 스레드가 공유 자원에 동시에 접근하면서 값을 읽고 쓰면 경쟁이 발생하고 데이터 일관성이 깨질 수 있다
- 데드락
- 두 개 이상의 스레드가 서로 다른 자원을 기다리면 무한 대기 상태에 빠지는 현상이다
- 라이브락
- 스레드들이 서로의 진행을 방해하지 않기 위해 지속적으로 상태를 변경하지만 실제로 아무런 작업도 진행되지 않는 상태이다
- 기아 (Starvation)
- 특정 스레드가 자원을 획득하지 못하고 무한 대기 상태에 빠지는 현상이다
자원 관리 문제
- 과도한 컨텍스트 스위칭
- 스레드가 너무 많이 생성되면 많은 컨텍스트 스위칭으로 오버헤드가 증가하고 성능이 저하된다
- 메모리 누수
- 스레드가 종료되지 않고 계속해서 실행 중이거나, 스레드가 사용한 자원이 적절하게 해제되지 않으면 메모리 누수가 발생할 수 있다
예외 처리 문제
- 스레드 내부에서 발생하는 예외가 적절히 처리되지 않으면 스레드가 예기치 않게 종료될 수 있다
성능 문제
- 너무 많은 스레드가 생기면 CPU 자원 분배에 부담이 생기고 컨텍스트 스위칭 오버헤드가 증가하며 성능이 저하된다
- 스레드 경쟁으로 자원 획득을 위해 대기하는 시간이 길어져 성능이 저하된다
테스트 및 디버깅의 어려움
- 동시성 문제는 테스트가 어렵다
이를 해결할 수 있는 방법 ?
- 스레드 풀 사용
- ExecutorService와 같은 스레드 풀을 사용해서 스레드 수를 제어하고 관리한다
- 스레드 풀
- 미리 스레드를 만들어두고 큐에 들어오는 작업을 스레드가 처리하는 구조를 갖춘 스레드 관리 기법이다
- 자바에서는 ExecutorService로 구현할 수 있다
- 적절한 스레드 수를 결정하는 기준은 앱 특성과 실행 환경을 고려해야 한다
- cpu 바운드
- 계산 작업을 많이 수행해서 cpu 사용량이 높은 편이다
- 일반적으로 cpu 바운드 작업의 경우 코어 수와 동일하거 약간 더 많은 스레드가 적합하다
- 이유는 스레드가 cpu 자원을 최대한 활용하는게 중요하기 때문이다
- 그렇지만 너무 많은 스레드는 컨텍스트 스위칭 오버헤드를 증가시킬 수 있다
- IO 바운드
- 파일 읽기/쓰기, 네트워크 통신, 데이터베이스 접근 등과 같은 입출력 작업이다
- cpu 사용량은 비교적 낮고, IO 대기 시간이 많은 작업이다
- 코어 수 * (1 + 평균 대기 시간 / 평균 작업 시간)으로 스레드 수를 구할 수 있다
- IO 바운드 작업은 더 많은 스레드를 사용할 수 있다
- 이유는 스레드가 IO작업을 기다리는 동안 다른 스레드가 cpu를 사용하도록해서 자원을 효율적으로 활용하는게 중요하다
- cpu 바운드
- 비동기 프로그래밍 사용
- 비동기 처리를하면 스레드 수를 줄이고 동시성에도 이점이 생긴다
- NIO
- 자바 1.4에서 도입된 새로운 IO API다
- 비동기식 방식과 채널, 버퍼를 사용해서 IO 작업을 효율적으로 처리할 수 있게 해준다
- 비동기식 방식을 지원
- 스레드가 IO 작업이 완료될 때까지 블로킹하지 않는다
- 기존의 블로킹 IO방식에서는 각 클라이언트 요청마다 별도의 스레드를 할당해야 했다
- 이는 블로킹 상태에 빠지게하고 IO작업이 완료될 때까지 아무 작업도 수행하지 않고 대기하게 만든다
- 이러면 많은 동시 접근을 처리할 때 스레드 수가 급격하게 늘어나는 문제가 생긴다
- NIO는 IO 작업이 완료될 때까지 스레드가 블로킹되지 않아서 적은 수의 스레드로 많은 수의 동시 연결을 처리할 수 있다
- 채널, 버퍼
- 데이터는 채널을 통해 읽고 쓰고 버퍼에 저장한다
- 채널과 버퍼를 사용해서 더 유연하고 효율적인 IO 처리가 가능하다
- 셀렉터
- 하나의 스레드가 여러 채널의 상태를 감시할 수 있게 해주는 매커니즘이다
- 각 채널에 읽기, 쓰기, 연결 요청 등의 이벤트를 등록한다
- 이벤트가 발생할 때까지 기다리고, 이벤트가 발생하면 해당 이벤트를 처리한다
- 이걸 멀티플렉싱이라고 한다
'TIL' 카테고리의 다른 글
CopyOnWriteArrayList은 어떻게 동시성 문제를 해결해주나? (0) | 2024.06.21 |
---|---|
임계영역을 알아보고 어떤 방법으로 구현할 수 있을까? (0) | 2024.06.18 |
ConcurrentHashMap은 어떤 방식으로 동시성 문제를 해결할까? (0) | 2024.06.16 |
프로세스가 있는데 왜 스레드가 필요한가? (0) | 2024.06.13 |
프록시 객체란 무엇인가? (0) | 2024.06.04 |