패스잇

CS 기초

동시성 / 멀티스레딩 면접 질문

동시성과 병렬성, 프로세스와 스레드, 멀티스레딩의 장단점, Race Condition과 방지법, 뮤텍스와 세마포어, 교착 상태의 4가지 조건과 해결, Java Memory Model의 happens-before와 volatile, CAS 기반 lock-free 큐, False Sharing. 동시성 면접은 용어 정의를 넘어 "어디서 경쟁이 생기고 어떤 비용으로 막는가"를 묻습니다. 멀티스레드 단골 질문을 모범답안과 함께 정리했습니다.

총 21문제 · 기초 7 · 중급 7 · 심화 7 · 모범답안 포함

동시성 / 멀티스레딩 면접 질문 · 기초

Q1 기초

동시성(Concurrency)과 병렬성(Parallelism)의 개념을 정의하고, 두 개념의 주요 차이점을 설명해 주세요.

힌트 · 동시성은 여러 작업을 동시에 처리하는 것처럼 보이는 것이고, 병렬성은 여러 작업을 실제로 동시에 처리하는 것입니다. CPU 코어 수와 관련하여 차이를 설명할 수 있습니다.

면접관님, 동시성과 병렬성은 둘 다 여러 작업을 동시에 처리하는 방식이지만, 핵심적인 차이가 있습니다.

전체 모범답안 펼치기

면접관님, 동시성과 병렬성은 둘 다 여러 작업을 동시에 처리하는 방식이지만, 핵심적인 차이가 있습니다.

동시성은 하나의 CPU 코어에서 여러 작업을 번갈아 가며 실행하여 마치 동시에 처리되는 것처럼 보이게 하는 것입니다. 예를 들어, 웹 브라우저에서 여러 탭을 열어놓고 사용하는 경우가 동시성의 예시입니다. 각 탭은 짧은 시간 동안 CPU를 점유하며 번갈아 실행되죠.

반면, 병렬성은 여러 개의 CPU 코어를 사용하여 여러 작업을 실제로 동시에 처리하는 것입니다. 예를 들어, 이미지 편집 프로그램에서 여러 필터를 동시에 적용하는 경우가 병렬성의 예시입니다. 각 필터는 서로 다른 CPU 코어에서 동시에 실행되므로 작업 시간이 단축됩니다.

따라서, 동시성은 자원(CPU)을 공유하여 시간을 분할하는 방식이고, 병렬성은 자원을 복제하여 실제로 동시에 작업을 처리하는 방식이라고 할 수 있습니다. 병렬성은 여러 개의 CPU 코어가 필요하지만, 동시성은 단일 코어에서도 구현될 수 있습니다.

#동시성#병렬성#자원 공유#실행 단위#CPU 코어

이 질문 단독 페이지 →

Q2 기초

프로세스(Process)와 스레드(Thread)는 운영체제에서 작업을 처리하는 단위입니다. 이 둘의 주요 차이점은 무엇이며, 각각 어떤 특징을 가지고 있는지 설명해 주세요.

힌트 · 프로세스는 독립적인 메모리 공간을 가지며, 스레드는 같은 프로세스 내에서 메모리를 공유합니다. 컨텍스트 스위칭 비용도 중요한 차이점입니다.

프로세스와 스레드는 운영체제에서 작업을 처리하는 기본적인 단위입니다. 가장 큰 차이점은 자원 공유 방식에 있습니다.

전체 모범답안 펼치기

프로세스와 스레드는 운영체제에서 작업을 처리하는 기본적인 단위입니다. 가장 큰 차이점은 자원 공유 방식에 있습니다.

프로세스는 독립적인 메모리 공간을 가지고 실행되기 때문에, 다른 프로세스의 자원에 직접 접근할 수 없습니다. 반면, 스레드는 하나의 프로세스 내에서 생성되어 프로세스의 메모리 공간과 자원을 공유합니다.

이러한 차이점 때문에 컨텍스트 스위칭 비용에도 차이가 발생합니다. 프로세스 간의 컨텍스트 스위칭은 메모리 공간을 변경해야 하므로 비용이 큰 반면, 스레드 간의 컨텍스트 스위칭은 메모리 공간 공유로 인해 비교적 비용이 적게 듭니다.

프로세스는 독립적인 실행 환경을 제공하여 안정성이 높지만, 자원 공유가 어렵고 생성 및 관리 비용이 높습니다. 스레드는 자원 공유가 용이하고 컨텍스트 스위칭 비용이 적어 효율적이지만, 동기화 문제 발생 가능성이 있고 하나의 스레드 오류가 전체 프로세스에 영향을 줄 수 있다는 단점이 있습니다.

#자원 공유#독립적인 실행#컨텍스트 스위칭#메모리 공간#병행성

이 질문 단독 페이지 →

Q3 기초

멀티스레딩(Multithreading)이란 무엇이며, 멀티스레딩을 사용할 때 얻을 수 있는 장점과 발생할 수 있는 단점은 무엇인지 설명해 주세요.

힌트 · 멀티스레딩은 CPU 활용률을 높여 성능 향상을 가져올 수 있지만, 동기화 문제와 디버깅의 어려움을 유발할 수 있습니다.

멀티스레딩은 하나의 프로세스 내에서 여러 개의 스레드를 동시에 실행하는 방식입니다. 이를 통해 CPU 활용률을 높여 전체적인 프로그램 성능을 향상시킬 수 있습니다. 예를 들어, 하나의 스레드가 I/O 작업을 기다리는…

전체 모범답안 펼치기

멀티스레딩은 하나의 프로세스 내에서 여러 개의 스레드를 동시에 실행하는 방식입니다. 이를 통해 CPU 활용률을 높여 전체적인 프로그램 성능을 향상시킬 수 있습니다. 예를 들어, 하나의 스레드가 I/O 작업을 기다리는 동안 다른 스레드가 계산 작업을 수행할 수 있습니다.

장점으로는 응답성 향상과 자원 효율성 증가가 있습니다. 하지만 단점도 존재합니다. 여러 스레드가 공유 자원에 동시에 접근할 때 발생하는 동기화 문제가 대표적입니다. 또한, 스레드 간의 컨텍스트 스위칭으로 인한 오버헤드가 발생할 수 있고, 교착 상태와 같은 문제로 인해 디버깅이 어려워질 수 있습니다. 따라서 멀티스레딩을 사용할 때는 이러한 잠재적인 문제점을 고려하여 신중하게 설계해야 합니다.

#병렬성#동시성#자원 공유#컨텍스트 스위칭#교착 상태

이 질문 단독 페이지 →

Q4 기초

멀티스레딩 환경에서 발생할 수 있는 '경쟁 조건(Race Condition)'이란 무엇이며, 어떤 상황에서 발생할 수 있는지 구체적인 예를 들어 설명해 주세요.

힌트 · 여러 스레드가 공유 자원에 동시에 접근하여 예상치 못한 결과를 초래하는 상황입니다. 변수 값 증가/감소 연산 시 발생할 수 있습니다.

경쟁 조건은 멀티스레딩 환경에서 여러 스레드가 공유 자원에 동시에 접근하려 할 때 발생하는 문제입니다. 이때, 스레드들의 실행 순서에 따라 예상치 못한 결과가 나올 수 있습니다.

전체 모범답안 펼치기

경쟁 조건은 멀티스레딩 환경에서 여러 스레드가 공유 자원에 동시에 접근하려 할 때 발생하는 문제입니다. 이때, 스레드들의 실행 순서에 따라 예상치 못한 결과가 나올 수 있습니다.

예를 들어, 전역 변수 count를 증가시키는 상황을 생각해 봅시다. 두 스레드가 동시에 count++ 연산을 수행하면, 각 스레드는 현재 count 값을 읽고, 1을 더한 후, 다시 count에 저장합니다. 만약 두 스레드가 거의 동시에 count 값을 읽었다면, 둘 다 같은 값에 1을 더해서 저장하게 되고, 결과적으로 count는 2가 아닌 1만 증가할 수 있습니다.

이러한 문제를 해결하기 위해 임계 영역을 설정하고, 상호 배제 기법(뮤텍스, 세마포어 등)을 사용하여 한 번에 하나의 스레드만 임계 영역에 접근하도록 동기화해야 합니다. 또한, 원자적인 연산을 사용하여 중간에 인터럽트되지 않도록 하는 것도 방법입니다.

#경쟁 조건#임계 영역#상호 배제#동기화#원자성

이 질문 단독 페이지 →

Q5 기초

경쟁 조건을 방지하기 위해 사용되는 '임계 영역(Critical Section)'의 개념을 설명하고, 왜 임계 영역 설정이 중요한지 이야기해 주세요.

힌트 · 임계 영역은 한 번에 하나의 스레드만 접근하도록 허용된 코드 블록입니다. 이를 통해 공유 자원의 무결성을 보호할 수 있습니다.

임계 영역은 여러 스레드가 동시에 접근하면 문제가 발생하는 공유 자원에 접근하는 코드 영역을 말합니다. 경쟁 조건 발생을 막기 위해, 임계 영역에는 한 번에 하나의 스레드만 접근하도록 제한합니다.

전체 모범답안 펼치기

임계 영역은 여러 스레드가 동시에 접근하면 문제가 발생하는 공유 자원에 접근하는 코드 영역을 말합니다. 경쟁 조건 발생을 막기 위해, 임계 영역에는 한 번에 하나의 스레드만 접근하도록 제한합니다.

임계 영역 설정이 중요한 이유는 공유 자원의 무결성을 보장하기 때문입니다. 만약 여러 스레드가 동시에 공유 변수를 수정하려고 하면, 예상치 못한 결과가 발생할 수 있습니다. 임계 영역을 통해 상호 배제를 구현함으로써 이러한 문제를 예방하고, 프로그램의 안정성을 확보할 수 있습니다. 예를 들어, 은행 계좌 잔액을 업데이트하는 코드가 임계 영역으로 보호되지 않으면, 여러 거래가 동시에 발생할 때 잔액이 잘못 계산될 수 있습니다.

#상호 배제#진행#한정된 대기#경쟁 조건#동기화

이 질문 단독 페이지 →

Q6 기초

동기화 메커니즘으로 사용되는 '뮤텍스(Mutex)'와 '세마포어(Semaphore)'의 개념을 정의하고, 이 둘의 주요 차이점은 무엇인지 설명해 주세요.

힌트 · 뮤텍스는 상호 배제를 위한 잠금 메커니즘이며, 세마포어는 여러 개의 자원에 대한 접근을 제어할 수 있는 카운터 기반 메커니즘입니다.

뮤텍스와 세마포어는 모두 동기화 메커니즘이지만, 목적과 동작 방식에 차이가 있습니다.

전체 모범답안 펼치기

뮤텍스와 세마포어는 모두 동기화 메커니즘이지만, 목적과 동작 방식에 차이가 있습니다.

뮤텍스는 상호 배제(Mutual Exclusion)를 위한 잠금 도구입니다. 특정 시점에 단 하나의 스레드만 공유 자원에 접근하도록 보장합니다. 뮤텍스는 '소유' 개념이 있어서, 잠금을 획득한 스레드만이 잠금을 해제할 수 있습니다.

반면, 세마포어는 여러 개의 자원에 대한 접근을 제어하는 데 사용됩니다. 세마포어는 내부적으로 카운터를 가지고 있으며, 이 카운터 값을 통해 접근 가능한 자원의 수를 나타냅니다. 스레드가 자원을 사용하려면 세마포어 값을 감소시키고, 사용이 끝나면 값을 증가시킵니다. 세마포어는 뮤텍스와 달리 잠금을 획득한 스레드가 반드시 잠금을 해제할 필요는 없습니다. 다른 스레드가 해제할 수도 있습니다.

주요 차이점은 뮤텍스는 하나의 스레드만 접근 가능한 자원에 사용되고, 소유 개념이 있다는 점입니다. 세마포어는 여러 개의 자원에 대한 접근을 제어하며, 소유 개념이 없습니다. 세마포어는 카운터 값을 통해 접근 가능한 자원 수를 관리합니다.

#상호 배제#소유 가능#카운팅 세마포어#바이너리 세마포어#자원 접근 제어

이 질문 단독 페이지 →

Q7 기초

'데드락(Deadlock)'이란 무엇이며, 데드락이 발생하기 위한 4가지 필수 조건을 설명해 주세요.

힌트 · 데드락은 두 개 이상의 스레드가 서로의 자원을 기다리며 무한히 블록되는 상태입니다. 상호 배제, 점유 및 대기, 비선점, 순환 대기가 필수 조건입니다.

데드락은 두 개 이상의 스레드 또는 프로세스가 서로가 점유하고 있는 자원을 기다리면서 무한정 멈춰있는 상태를 말합니다. 마치 교착 상태에 빠진 것과 같죠.

전체 모범답안 펼치기

데드락은 두 개 이상의 스레드 또는 프로세스가 서로가 점유하고 있는 자원을 기다리면서 무한정 멈춰있는 상태를 말합니다. 마치 교착 상태에 빠진 것과 같죠.

데드락이 발생하려면 네 가지 필수 조건이 모두 충족되어야 합니다.

첫째, 상호 배제(Mutual Exclusion)입니다. 자원은 한 번에 하나의 스레드만 사용할 수 있어야 합니다.

둘째, 점유 및 대기(Hold and Wait)입니다. 스레드가 이미 자원을 점유한 상태에서 다른 자원을 기다려야 합니다.

셋째, 비선점(No Preemption)입니다. 스레드가 점유한 자원은 강제로 뺏을 수 없어야 합니다.

넷째, 순환 대기(Circular Wait)입니다. 스레드들이 자원을 서로 순환적으로 기다리는 관계가 형성되어야 합니다. 예를 들어, 스레드 A는 스레드 B가 가진 자원을 기다리고, 스레드 B는 스레드 A가 가진 자원을 기다리는 상황입니다.

#상호 배제#점유 대기#비선점#순환 대기#자원 할당 그래프

이 질문 단독 페이지 →

읽기만으론 부족합니다. 직접 말해보세요

패스잇 앱에서 동시성 / 멀티스레딩 질문에 직접 답하면 AI가 1:1로 답변을 코칭합니다.

동시성 / 멀티스레딩 면접 질문 · 중급

Q8 중급

뮤텍스와 세마포어는 동기화 메커니즘으로 사용됩니다. 두 메커니즘의 주요 차이점을 설명하고, 각각 어떤 상황에서 더 적합하게 사용될 수 있는지 구체적인 예시를 들어 설명해주세요.

힌트 · 뮤텍스는 상호 배제를 위한 잠금 메커니즘이며, 세마포어는 리소스에 대한 접근을 제어하는 카운팅 메커니즘입니다. 각각 단일 리소스와 다중 리소스 접근 제어에 활용됩니다.

뮤텍스와 세마포어는 둘 다 동기화 메커니즘이지만, 주요 차이점은 뮤텍스는 상호 배제를 위한 잠금 도구이고, 세마포어는 리소스 접근을 제어하는 카운터라는 점입니다.

전체 모범답안 펼치기

뮤텍스와 세마포어는 둘 다 동기화 메커니즘이지만, 주요 차이점은 뮤텍스는 상호 배제를 위한 잠금 도구이고, 세마포어는 리소스 접근을 제어하는 카운터라는 점입니다.

뮤텍스는 특정 시점에 하나의 스레드만 공유 자원에 접근하도록 보장합니다. 마치 화장실 문에 걸쇠를 거는 것과 같습니다. 한 사람이 들어가면 다른 사람은 기다려야 합니다. 주로 단일 리소스에 대한 접근을 제어할 때 사용됩니다. 예를 들어, 공유 변수를 갱신하는 스레드 간의 충돌을 방지하는 데 유용합니다.

반면, 세마포어는 동시에 접근할 수 있는 리소스의 수를 제한합니다. 주차장과 비슷하다고 생각하면 됩니다. 주차 공간이 10개인 주차장은 세마포어 값이 10인 세마포어로 표현할 수 있습니다. 주로 다중 리소스에 대한 접근을 제어할 때 사용됩니다. 예를 들어, 데이터베이스 연결 풀에서 동시에 사용할 수 있는 연결 수를 제한하는 데 사용할 수 있습니다.

#상호 배제#소유 가능성#카운팅#리소스 관리#프로세스/스레드 동기화

이 질문 단독 페이지 →

Q9 중급

멀티스레드 환경에서 발생할 수 있는 Race Condition(경쟁 상태)이 무엇인지 정의하고, 이러한 문제를 방지하기 위한 대표적인 방법들을 설명해주세요. 실제 코드에서 Race Condition이 발생하는 시나리오를 예시로 들어 설명할 수 있다면 더욱 좋습니다.

힌트 · 경쟁 상태는 여러 스레드가 공유 데이터에 동시에 접근하여 예상치 못한 결과를 초래하는 상황입니다. 락, 뮤텍스, 세마포어, 원자적 연산 등을 통해 방지할 수 있습니다.

"경쟁 상태(Race Condition)는 멀티스레드 환경에서 여러 스레드가 공유 자원에 동시에 접근하려 할 때, 접근 순서에 따라 결과가 달라지는 상황을 말합니다. 예를 들어, 두 스레드가 동시에 하나의 변수를 증…

전체 모범답안 펼치기

"경쟁 상태(Race Condition)는 멀티스레드 환경에서 여러 스레드가 공유 자원에 동시에 접근하려 할 때, 접근 순서에 따라 결과가 달라지는 상황을 말합니다. 예를 들어, 두 스레드가 동시에 하나의 변수를 증가시키려 할 때, 예상과 달리 1만 증가하는 경우가 발생할 수 있습니다.

이러한 문제를 방지하기 위한 방법으로는 대표적으로 락(Lock) 또는 뮤텍스(Mutex)를 사용하는 것이 있습니다. 락을 사용하여 특정 코드 영역(Critical Section)에 하나의 스레드만 접근하도록 보장하는 것이죠. 세마포어는 락보다 더 일반적인 개념으로, 여러 개의 스레드가 동시에 접근 가능한 자원의 수를 제어할 수 있습니다. 또한, 간단한 연산의 경우 원자적 연산(Atomic Operation)을 사용하여 경쟁 상태를 피할 수 있습니다.

// 경쟁 상태 발생 예시
int counter = 0;

void increment() {
  counter++; // 여러 스레드가 동시에 접근하면 문제 발생 가능
}

위 코드에서 increment() 메서드를 여러 스레드가 동시에 실행하면 counter 값이 예상과 다르게 나올 수 있습니다."

#Race Condition#Critical Section#Mutex#Semaphore#Atomic Operation

이 질문 단독 페이지 →

Q10 중급

교착 상태(Deadlock)는 멀티스레드 애플리케이션에서 심각한 문제를 야기할 수 있습니다. 교착 상태의 4가지 필요조건을 설명하고, 이를 해결하거나 예방하기 위한 실용적인 방법들을 제시해주세요.

힌트 · 교착 상태는 상호 배제, 점유 및 대기, 비선점, 순환 대기라는 네 가지 조건이 동시에 만족될 때 발생합니다. 락 획득 순서 지정, 타임아웃, 자원 선점 등의 방법으로 예방 및 회피할 수 있습니다.

교착 상태는 멀티스레드 환경에서 여러 스레드가 서로 필요한 자원을 점유하고 놓아주지 않아 무한정 대기하는 상황을 말합니다. 발생 조건은 크게 네 가지입니다.

전체 모범답안 펼치기

교착 상태는 멀티스레드 환경에서 여러 스레드가 서로 필요한 자원을 점유하고 놓아주지 않아 무한정 대기하는 상황을 말합니다. 발생 조건은 크게 네 가지입니다.

첫째, 상호 배제입니다. 자원은 한 번에 하나의 스레드만 사용할 수 있어야 합니다. 둘째, 점유 및 대기입니다. 스레드가 자원을 점유한 상태에서 다른 자원을 기다려야 합니다. 셋째, 비선점입니다. 스레드가 점유한 자원은 강제로 뺏을 수 없습니다. 넷째, 순환 대기입니다. 스레드들이 서로 자원을 요구하며 순환 형태로 대기해야 합니다.

교착 상태를 해결하거나 예방하는 방법으로는 여러 가지가 있습니다. 가장 일반적인 방법은 락 획득 순서를 일관되게 유지하는 것입니다. 예를 들어, 항상 A 락을 먼저 획득하고 B 락을 획득하도록 규칙을 정하는 것이죠. 또한, 락 획득에 타임아웃을 설정하여 무한정 대기를 방지할 수 있습니다. 자원 할당 그래프를 활용하여 교착 상태 발생 가능성을 미리 탐지하고 회피하는 방법도 있습니다. 마지막으로, 자원 선점을 허용하는 것도 하나의 방법이 될 수 있지만, 자원 선점은 데드락 회피 방법 중 가장 복잡하고 오류 발생 가능성이 높습니다.

#상호 배제#점유 대기#비선점#순환 대기#자원 할당 그래프

이 질문 단독 페이지 →

Q11 중급

특정 언어(예: Java, C#)에서 `volatile` 키워드가 멀티스레딩 환경에서 어떤 역할을 하는지 설명해주세요. `volatile`이 보장하는 것과 보장하지 못하는 것을 구분하여 설명하고, `synchronized` 또는 `Atomic` 클래스와의 차이점을 언급해주세요.

힌트 · `volatile`은 변수의 변경 사항이 모든 스레드에 즉시 가시화되도록 보장하지만, 원자성을 보장하지는 않습니다. `synchronized`는 가시성과 원자성을 모두 보장하며, `Atomic` 클래스는 특정 연산에 대한 원자성을 보장합니다.

"네, volatile 키워드는 멀티스레딩 환경에서 변수의 가시성을 확보하는 데 중요한 역할을 합니다. 즉, volatile 변수의 값이 변경되면 즉시 메인 메모리에 반영되고, 다른 스레드들이 해당 변수를 읽을 때…

전체 모범답안 펼치기

"네, volatile 키워드는 멀티스레딩 환경에서 변수의 가시성을 확보하는 데 중요한 역할을 합니다. 즉, volatile 변수의 값이 변경되면 즉시 메인 메모리에 반영되고, 다른 스레드들이 해당 변수를 읽을 때 항상 최신 값을 읽도록 보장합니다. 이는 각 스레드의 캐시에 저장된 값이 오래되어 발생하는 데이터 불일치 문제를 해결하는 데 도움을 줍니다.

하지만 volatile은 원자성을 보장하지 않습니다. 예를 들어, volatile 변수에 대한 i++ 연산은 읽기, 증가, 쓰기 세 단계로 이루어지는데, 이 과정이 원자적으로 수행되지 않아 여러 스레드가 동시에 접근하면 데이터 경쟁이 발생할 수 있습니다.

synchronized 키워드는 가시성과 원자성을 모두 보장합니다. 특정 코드 블록을 synchronized로 감싸면 해당 블록은 한 번에 하나의 스레드만 실행할 수 있어 데이터 경쟁을 막고, 변경된 값이 즉시 모든 스레드에 보이도록 합니다.

AtomicInteger와 같은 Atomic 클래스는 특정 연산(예: 증가, 감소)에 대한 원자성을 보장합니다. CAS (Compare-and-Swap) 연산을 사용하여 동기화 문제를 해결하며, volatile 변수보다 더 복잡한 연산에 안전하게 사용할 수 있습니다."

#가시성#원자성#메모리 배리어#캐시 일관성#happens-before

이 질문 단독 페이지 →

Q12 중급

스레드 풀(Thread Pool)을 사용하는 주된 이유와 이점이 무엇인지 설명해주세요. 스레드 풀의 크기를 결정할 때 고려해야 할 요소들과, 잘못된 스레드 풀 사용으로 발생할 수 있는 문제점들을 함께 설명해주세요.

힌트 · 스레드 풀은 스레드 생성/소멸 오버헤드를 줄이고, 리소스 고갈을 방지하여 성능을 향상시킵니다. CPU 코어 수, 작업 유형(CPU-bound/IO-bound) 등을 고려하여 크기를 결정해야 합니다.

스레드 풀을 사용하는 주된 이유는 스레드 생성 및 소멸에 드는 비용을 줄여 성능을 향상시키기 위해서입니다. 스레드를 미리 생성해두고 작업 큐에 들어온 작업을 할당함으로써, 매번 스레드를 새로 만드는 오버헤드를 없애고…

전체 모범답안 펼치기

스레드 풀을 사용하는 주된 이유는 스레드 생성 및 소멸에 드는 비용을 줄여 성능을 향상시키기 위해서입니다. 스레드를 미리 생성해두고 작업 큐에 들어온 작업을 할당함으로써, 매번 스레드를 새로 만드는 오버헤드를 없애고 스레드를 재사용하여 자원 효율성을 높입니다. 또한, 스레드 수를 제한하여 시스템 자원 고갈을 방지하고 과도한 컨텍스트 스위칭으로 인한 성능 저하를 막을 수 있습니다.

스레드 풀 크기를 결정할 때는 CPU 코어 수, 작업 유형(CPU 바운드/IO 바운드) 등을 고려해야 합니다. CPU 바운드 작업은 코어 수에 맞춰 스레드 수를 설정하고, IO 바운드 작업은 더 많은 스레드를 할당하는 것이 좋습니다.

잘못된 스레드 풀 사용은 데드락이나 기아 상태를 유발할 수 있습니다. 예를 들어, 스레드 풀 내의 모든 스레드가 다른 스레드의 작업 완료를 기다리는 경우 데드락이 발생할 수 있습니다. 또한, 특정 작업에만 스레드가 계속 할당되어 다른 작업이 실행되지 못하는 기아 상태도 발생할 수 있습니다. 따라서 스레드 풀 크기를 적절하게 설정하고, 작업 간의 의존성을 신중하게 관리해야 합니다.

#스레드 재사용#자원 관리#컨텍스트 스위칭#CPU 바운드/I/O 바운드#데드락/기아 상태

이 질문 단독 페이지 →

Q13 중급

동시성 프로그래밍에서 불변 객체(Immutable Object)가 갖는 장점은 무엇이며, 어떻게 불변 객체를 설계하여 스레드 안전성을 높일 수 있는지 구체적인 방법을 설명해주세요. 단점이나 제약 사항도 있다면 함께 언급해주세요.

힌트 · 불변 객체는 상태가 변경되지 않아 여러 스레드가 동시에 접근해도 안전합니다. 모든 필드를 final로 선언하고, setter를 제공하지 않으며, 방어적 복사를 통해 스레드 안전성을 확보합니다.

면접관님, 동시성 프로그래밍에서 불변 객체는 스레드 안전성을 확보하는 데 매우 유용합니다. 왜냐하면 불변 객체는 생성 후 내부 상태가 변하지 않기 때문에 여러 스레드가 동시에 접근해도 데이터 경쟁 조건이 발생하지 않…

전체 모범답안 펼치기

면접관님, 동시성 프로그래밍에서 불변 객체는 스레드 안전성을 확보하는 데 매우 유용합니다. 왜냐하면 불변 객체는 생성 후 내부 상태가 변하지 않기 때문에 여러 스레드가 동시에 접근해도 데이터 경쟁 조건이 발생하지 않기 때문입니다.

불변 객체를 설계하는 방법은 다음과 같습니다. 첫째, 클래스의 모든 필드를 final로 선언하여 변경을 막습니다. 둘째, 객체의 상태를 변경하는 setter 메서드를 제공하지 않습니다. 셋째, 가변 객체를 필드로 가질 경우, 생성자에서 방어적 복사를 수행하여 외부에서 객체 내부의 가변 상태를 변경하는 것을 방지합니다.

하지만 불변 객체는 모든 변경 사항에 대해 새로운 객체를 생성해야 하므로, 객체 생성 비용이 증가할 수 있습니다. 또한, 복잡한 객체의 경우 불변성을 유지하기 위한 코드가 복잡해질 수 있다는 단점도 있습니다.

#스레드 안전성#불변성#공유 상태#얕은 복사#방어적 복사

이 질문 단독 페이지 →

Q14 중급

멀티스레딩 환경에서 문맥 교환(Context Switching)이 발생하는 시점과 그 과정에 대해 설명해주세요. 문맥 교환이 시스템 성능에 미치는 영향은 무엇이며, 이를 최소화하기 위한 방법에는 어떤 것들이 있는지 설명해주세요.

힌트 · 문맥 교환은 CPU가 한 스레드에서 다른 스레드로 제어를 넘길 때 발생하며, 레지스터, 프로그램 카운터 등의 상태를 저장하고 복원하는 오버헤드가 발생합니다. 락 최소화, 스레드 수 조절 등으로 오버헤드를 줄일 수 있습니다.

문맥 교환은 멀티스레딩 환경에서 CPU가 실행 중인 스레드를 일시 중단하고 다른 스레드를 실행하기 위해 현재 스레드의 상태를 저장하고 새로운 스레드의 상태를 복원하는 과정입니다. 주로 다음과 같은 시점에 발생합니다.

전체 모범답안 펼치기

문맥 교환은 멀티스레딩 환경에서 CPU가 실행 중인 스레드를 일시 중단하고 다른 스레드를 실행하기 위해 현재 스레드의 상태를 저장하고 새로운 스레드의 상태를 복원하는 과정입니다. 주로 다음과 같은 시점에 발생합니다.

  • 인터럽트 발생: 타이머 인터럽트, I/O 인터럽트 등으로 인해 현재 스레드의 실행을 중단해야 할 때
  • 스레드 블로킹: I/O 작업 완료 대기, 락 획득 대기 등으로 스레드가 스스로 블로킹될 때
  • 스케줄링 알고리즘: 운영체제의 스케줄러가 우선순위 또는 시간 할당량에 따라 스레드를 교체할 때

문맥 교환은 스레드 상태 저장 및 복원 과정에서 오버헤드를 발생시키고, 캐시 미스를 증가시켜 시스템 성능에 부정적인 영향을 미칠 수 있습니다.

문맥 교환 오버헤드를 최소화하기 위한 방법으로는 다음과 같은 것들이 있습니다.

  • 락 사용 최소화: 락 경쟁을 줄여 불필요한 문맥 교환을 방지합니다.
  • 스레드 풀 사용: 스레드 생성 및 소멸 비용을 줄여 문맥 교환 빈도를 낮춥니다.
  • 적절한 스레드 수 유지: 너무 많은 스레드는 오히려 문맥 교환 오버헤드를 증가시키므로, CPU 코어 수에 맞춰 적절한 스레드 수를 유지합니다.
  • 효율적인 스케줄링 알고리즘: 운영체제의 스케줄링 알고리즘을 조정하여 문맥 교환 빈도를 최적화합니다.
#인터럽트#스레드 상태 저장#스케줄링 알고리즘#캐시 미스#스레드 풀

이 질문 단독 페이지 →

동시성 / 멀티스레딩 면접 질문 · 심화

Q15 심화

Java Memory Model (JMM)의 happens-before 관계에 대해 설명하고, volatile 키워드가 JMM 관점에서 어떻게 가시성(visibility)과 순서(ordering)를 보장하는지 내부 동작 원리를 상세히 설명해 주십시오.

힌트 · JMM은 스레드 간 메모리 가시성 규칙을 정의합니다. volatile은 read/write 시 memory barrier를 삽입하여 컴파일러 및 CPU의 재정렬을 방지하고 캐시 일관성을 보장합니다.

Java Memory Model (JMM)의 happensbefore 관계는 한 스레드 내의 연산 순서뿐 아니라 스레드 간의 연산 순서에 대한 규칙을 정의합니다. A happensbefore B라면, A의 결과가 B…

전체 모범답안 펼치기

Java Memory Model (JMM)의 happens-before 관계는 한 스레드 내의 연산 순서뿐 아니라 스레드 간의 연산 순서에 대한 규칙을 정의합니다. A happens-before B라면, A의 결과가 B에게 반드시 보여지는 것을 보장합니다. 즉, A가 B보다 먼저 실행된 결과를 B가 볼 수 있다는 의미입니다.

volatile 키워드는 JMM 관점에서 변수의 가시성과 순서화를 보장합니다. volatile 변수에 대한 쓰기 연산은 항상 메인 메모리에 직접 쓰여지고, 읽기 연산은 항상 메인 메모리에서 읽어옵니다. 이는 각 CPU 코어의 캐시에 저장된 값을 무시하고, 항상 최신 값을 사용하도록 강제합니다.

내부적으로 volatile은 읽기/쓰기 연산 앞뒤에 메모리 배리어(Memory Barrier)를 삽입합니다. 쓰기 배리어는 쓰기 연산이 캐시에만 머무르지 않고 메인 메모리에 즉시 반영되도록 하고, 읽기 배리어는 캐시에서 값을 읽지 않고 메인 메모리에서 최신 값을 읽어오도록 합니다. 이러한 메모리 배리어는 컴파일러와 CPU의 명령어 재정렬을 막아, volatile 변수에 대한 연산 순서가 프로그램 코드에 명시된 순서대로 실행되도록 보장합니다. 결과적으로 volatile은 스레드 간 데이터 경쟁 상황을 방지하고, 예측 가능한 동시성 프로그래밍을 가능하게 합니다.

#Happens-Before#가시성(Visibility)#순서화(Ordering)#메모리 배리어(Memory Barrier)#캐시 일관성(Cache Coherence)

이 질문 단독 페이지 →

Q16 심화

락(Lock)을 사용하지 않고 스레드 안전한(thread-safe) 큐를 구현한다고 가정할 때, 어떤 기법들을 활용할 수 있으며, 특히 CAS(Compare-And-Swap) 연산을 사용하여 어떻게 원자성(atomicity)을 보장할 수 있는지 구체적인 예시와 함께 설명해 주십시오. 락 프리(lock-free) 방식의 장단점은 무엇입니까?

힌트 · CAS는 메모리 위치의 현재 값을 예상 값과 비교하여 같으면 새 값으로 원자적으로 업데이트합니다. ABA 문제는 태그드 포인터나 참조 카운터를 통해 해결할 수 있으며, 락 프리 방식은 데드락 위험을 줄이고 확장성을 향상시키지만 구현이 복잡합니다.

락 없이 스레드 안전한 큐를 구현하려면 CAS(CompareAndSwap)와 같은 원자적 연산을 활용하는 락 프리(lockfree) 기법을 사용할 수 있습니다. CAS는 특정 메모리 위치의 값이 예상 값과 같을 때만…

전체 모범답안 펼치기

락 없이 스레드 안전한 큐를 구현하려면 CAS(Compare-And-Swap)와 같은 원자적 연산을 활용하는 락 프리(lock-free) 기법을 사용할 수 있습니다. CAS는 특정 메모리 위치의 값이 예상 값과 같을 때만 새 값으로 업데이트하는 연산으로, 이를 통해 여러 스레드가 동시에 데이터를 수정하려 할 때 발생할 수 있는 경쟁 상태를 방지하고 원자성을 보장합니다.

예를 들어, 큐의 tail 포인터를 업데이트할 때 CAS를 사용할 수 있습니다. 새로운 노드를 추가할 때, 현재 tail 포인터 값을 읽어온 후, 해당 값이 여전히 이전과 같다면 새 노드를 가리키도록 tail 포인터를 원자적으로 업데이트합니다. 만약 다른 스레드가 먼저 tail을 변경했다면 CAS 연산은 실패하고, 다시 현재 tail 값을 읽어와 시도하는 과정을 반복합니다.

CAS를 사용하면 데드락 위험이 없고 컨텍스트 스위칭 오버헤드가 줄어 확장성이 좋다는 장점이 있습니다. 하지만 ABA 문제(값은 같지만 실제로는 다른 시점에 변경된 경우)가 발생할 수 있으며, 이를 해결하기 위해 태그드 포인터나 참조 카운터 같은 추가적인 기법이 필요합니다. 또한, 락 프리 알고리즘은 구현이 복잡하고 디버깅이 어렵다는 단점이 있습니다.

#CAS (Compare-And-Swap)#원자적 연산#ABA 문제#메모리 배리어#락 프리 (Lock-Free)

이 질문 단독 페이지 →

Q17 심화

멀티스레드 환경에서 캐시 일관성(cache coherence)과 관련된 문제 중 'False Sharing'이 무엇인지 설명하고, 이로 인해 발생하는 성능 저하 문제를 어떻게 진단하고 해결할 수 있는지 구체적인 방안을 제시해 주십시오.

힌트 · False Sharing은 서로 다른 스레드가 독립적인 데이터를 수정함에도 불구하고 같은 캐시 라인에 위치하여 불필요한 캐시 동기화 오버헤드를 유발하는 현상입니다. 데이터 구조 패딩(padding)을 통해 캐시 라인 분리를 유도하여 해결할 수 있습니다.

네, 멀티스레드 환경에서의 False Sharing에 대해 설명드리겠습니다.

전체 모범답안 펼치기

네, 멀티스레드 환경에서의 False Sharing에 대해 설명드리겠습니다.

False Sharing은 서로 다른 스레드가 독립적인 데이터를 수정하려 할 때, 해당 데이터들이 같은 캐시 라인에 위치하게 되어 발생하는 문제입니다. CPU는 캐시 라인을 단위로 데이터를 관리하기 때문에, 한 스레드가 특정 캐시 라인을 수정하면 다른 스레드에서 해당 캐시 라인을 사용하려 할 때 무효화(invalidation)가 발생합니다. 이로 인해 불필요한 캐시 동기화 오버헤드가 발생하여 성능이 저하됩니다.

성능 저하 진단은 주로 성능 프로파일링 도구를 사용하여 특정 스레드의 캐시 관련 지표(예: 캐시 미스율, 캐시 라인 무효화 횟수)를 분석함으로써 이루어집니다.

해결 방안으로는 데이터 구조 패딩(padding)이 가장 효과적입니다. 각 스레드가 접근하는 변수들을 서로 다른 캐시 라인에 배치되도록 데이터 구조에 빈 공간을 추가하는 것입니다. 예를 들어, 구조체 멤버들 사이에 더미 변수를 삽입하거나, 구조체 자체를 캐시 라인 크기의 배수로 정렬하는 방식으로 False Sharing을 방지할 수 있습니다.

#False Sharing#캐시 라인#성능 프로파일링#데이터 패딩#구조체 정렬

이 질문 단독 페이지 →

Q18 심화

분산 시스템 또는 복잡한 마이크로서비스 환경에서 발생할 수 있는 교착 상태(deadlock)를 예방하거나 탐지하기 위한 고급 전략에는 어떤 것들이 있으며, 각 전략의 구현 복잡도와 실제 적용 시의 고려사항은 무엇인지 설명해 주십시오.

힌트 · 자원 할당 순서 지정, 타임아웃 및 재시도, 데드락 탐지 알고리즘(예: 데드락 그래프) 등이 있습니다. 분산 환경에서는 분산 트랜잭션 관리나 분산 락 매니저를 활용할 수 있습니다.

분산 시스템에서 교착 상태는 심각한 문제죠. 이를 예방하거나 탐지하기 위한 고급 전략으로는 크게 두 가지 접근 방식이 있습니다.

전체 모범답안 펼치기

분산 시스템에서 교착 상태는 심각한 문제죠. 이를 예방하거나 탐지하기 위한 고급 전략으로는 크게 두 가지 접근 방식이 있습니다.

첫째, 교착 상태 회피입니다. 가장 대표적인 방법은 자원 할당 순서 지정입니다. 모든 프로세스가 자원을 요청할 때 미리 정해진 순서대로 요청하도록 강제하는 거죠. 이렇게 하면 순환 대기 조건을 원천적으로 방지할 수 있습니다. 구현은 비교적 간단하지만, 모든 자원에 대한 전역적인 순서를 정의하기 어렵거나 성능 저하를 야기할 수 있다는 단점이 있습니다.

둘째, 교착 상태 탐지 및 복구입니다. 시스템에서 주기적으로 자원 할당 그래프를 생성하고 순환 대기를 탐지하는 알고리즘을 사용합니다. 분산 환경에서는 분산 잠금 관리자를 통해 잠금 상태를 중앙에서 관리하거나, 타임아웃 및 재시도 메커니즘을 활용하여 특정 시간 내에 응답이 없으면 잠금을 해제하고 재시도하는 방식도 많이 사용됩니다. 타임아웃은 구현이 쉽지만, 실제 교착 상태가 아닌 경우에도 불필요한 재시도를 유발할 수 있습니다. 분산 잠금 관리자는 복잡성이 높고 단일 실패 지점이 될 수 있다는 점을 고려해야 합니다.

실제 적용 시에는 시스템의 특성, 성능 요구사항, 복잡성 등을 종합적으로 고려하여 적절한 전략을 조합하는 것이 중요합니다.

#교착 상태 회피#타임아웃#분산 잠금#리소스 할당 그래프#순환 대기 탐지

이 질문 단독 페이지 →

Q19 심화

Java의 synchronized 키워드와 ReentrantLock 클래스의 내부 구현 메커니즘을 비교하고, 특히 ReentrantLock이 synchronized보다 제공하는 유연성과 고급 기능(예: 조건 변수, 공정성)이 어떻게 구현되는지 AQS(AbstractQueuedSynchronizer)를 중심으로 설명해 주십시오.

힌트 · synchronized는 JVM 모니터 기반이며 AQS를 사용하지 않습니다. ReentrantLock은 AQS를 기반으로 락 획득/해제 로직을 구현하며, CAS를 이용한 상태 관리와 대기 큐를 통해 조건 변수 및 공정성 모드를 제공합니다.

synchronized와 ReentrantLock은 모두 스레드 동기화를 위한 도구지만, 내부 구현 방식과 제공하는 기능에 차이가 있습니다.

전체 모범답안 펼치기

synchronized와 ReentrantLock은 모두 스레드 동기화를 위한 도구지만, 내부 구현 방식과 제공하는 기능에 차이가 있습니다.

synchronized는 JVM의 모니터(monitor) 메커니즘을 기반으로 동작합니다. 각 객체는 모니터 락을 가지며, synchronized 블록이나 메소드에 진입하면 해당 객체의 모니터 락을 획득합니다. 락 획득 및 해제는 JVM 레벨에서 관리되며, 별도의 대기 큐나 조건 변수 기능을 직접적으로 제공하지 않습니다.

반면 ReentrantLock은 java.util.concurrent.locks.AbstractQueuedSynchronizer (AQS)를 기반으로 구현됩니다. AQS는 스레드 동기화를 위한 프레임워크로, CAS(Compare-And-Swap) 연산을 이용해 상태를 관리하고, 공정성(fairness) 모드와 조건 변수(Condition)를 지원합니다.

ReentrantLock의 유연성은 AQS 덕분입니다. AQS는 스레드들이 락을 획득하기 위해 대기하는 큐를 관리하며, 이를 통해 조건 변수(Condition)를 구현합니다. newCondition() 메소드로 생성된 Condition 객체는 await()와 signal()/signalAll() 메소드를 통해 스레드를 특정 조건에서 대기시키거나 깨울 수 있습니다. 또한, ReentrantLock은 생성자에서 fair=true 옵션을 통해 공정성 모드를 지원하는데, 이는 AQS가 대기 큐의 순서대로 락을 할당하도록 하여 모든 스레드가 락을 획득할 기회를 공평하게 갖도록 합니다.

요약하자면, synchronized는 JVM 레벨의 간편한 동기화 도구이고, ReentrantLock은 AQS를 통해 더 세밀한 제어와 고급 기능(조건 변수, 공정성)을 제공하는 강력한 동기화 도구입니다.

#synchronized#ReentrantLock#AQS#조건 변수#공정성

이 질문 단독 페이지 →

Q20 심화

멀티코어 환경에서 동시성 애플리케이션의 성능을 논할 때, 확장성(scalability)과 처리량(throughput)은 어떤 관계를 가지며, 특정 워크로드에서 이 두 가지 지표를 최대화하기 위한 동시성 설계 전략은 어떻게 달라져야 하는지 구체적인 사례를 들어 설명해 주십시오.

힌트 · 확장성은 더 많은 자원을 추가했을 때 성능이 얼마나 선형적으로 증가하는지를 나타내며, 처리량은 단위 시간당 완료되는 작업의 양입니다. Amdahl의 법칙은 병렬화 가능한 부분의 비율이 확장성에 미치는 영향을 보여주며, 동시성 설계 시 공유 자원 경합을 최소화하고 작업 분할 전략을 최적화해야 합니다.

멀티코어 환경에서 확장성과 처리량은 동시성 애플리케이션 성능의 핵심 지표입니다. 확장성은 코어 수를 늘렸을 때 성능이 얼마나 비례적으로 향상되는지를, 처리량은 단위 시간당 얼마나 많은 작업을 완료하는지를 나타냅니다.

전체 모범답안 펼치기

멀티코어 환경에서 확장성과 처리량은 동시성 애플리케이션 성능의 핵심 지표입니다. 확장성은 코어 수를 늘렸을 때 성능이 얼마나 비례적으로 향상되는지를, 처리량은 단위 시간당 얼마나 많은 작업을 완료하는지를 나타냅니다.

이 둘은 밀접하게 연관되어 있지만, 항상 비례하지는 않습니다. 암달의 법칙에 따르면, 애플리케이션의 순차적인 부분은 아무리 많은 코어를 추가해도 성능 향상에 한계가 있습니다. 따라서 확장성을 높이려면 병렬화 가능한 부분을 최대화해야 합니다.

처리량을 최대화하기 위해서는 공유 자원 경합(Lock contention)을 최소화하고, 작업 분할 전략을 최적화하는 것이 중요합니다. 예를 들어, 데이터베이스 접근 시 락을 최소화하기 위해 읽기/쓰기 분리, 비관적 락 대신 낙관적 락을 사용하거나, 아예 락이 필요 없는 데이터 구조를 사용하는 것을 고려할 수 있습니다.

워크로드에 따라 전략은 달라집니다. CPU 바운드 워크로드에서는 작업 분할을 통해 여러 코어에 작업을 분산시키는 것이 확장성과 처리량 모두에 효과적입니다. 반면 I/O 바운드 워크로드에서는 비동기 프로그래밍을 통해 I/O 대기 시간을 최소화하여 전체 처리량을 높이는 데 집중해야 합니다. 예를 들어, 웹 서버는 수많은 동시 요청을 처리해야 하므로, 논블로킹 I/O와 이벤트 기반 아키텍처를 사용하여 확장성과 처리량을 극대화합니다.

#암달의 법칙#병목 현상#Lock contention#데이터 분할#비동기 프로그래밍

이 질문 단독 페이지 →

Q21 심화

기존 스레드 기반의 동시성 모델(shared-memory concurrency)과 비동기 프로그래밍 모델(예: Actor Model, CSP)을 비교하고, 각각의 모델이 특정 유형의 문제(I/O 바운드 vs. CPU 바운드)에 어떻게 더 적합한지, 그리고 발생할 수 있는 트레이드오프(trade-off)는 무엇인지 설명해 주십시오.

힌트 · 스레드 기반 모델은 공유 메모리를 통해 상태를 공유하며, 비동기 모델은 메시지 패싱을 통해 상태를 격리합니다. I/O 바운드 작업에는 비동기 모델이 컨텍스트 스위칭 오버헤드를 줄여 효율적이며, CPU 바운드 작업에는 스레드 기반 모델이 병렬 처리에 유리할 수 있습니다.

기존 스레드 기반 동시성은 공유 메모리를 통해 데이터를 공유하며, 여러 스레드가 동시에 같은 메모리에 접근할 때 동기화 문제가 발생합니다. 이는 CPU 바운드 작업에서 병렬 처리에 유리하지만, 컨텍스트 스위칭 오버헤…

전체 모범답안 펼치기

기존 스레드 기반 동시성은 공유 메모리를 통해 데이터를 공유하며, 여러 스레드가 동시에 같은 메모리에 접근할 때 동기화 문제가 발생합니다. 이는 CPU 바운드 작업에서 병렬 처리에 유리하지만, 컨텍스트 스위칭 오버헤드가 커질 수 있습니다.

반면 Actor 모델이나 CSP 같은 비동기 프로그래밍은 메시지 패싱을 통해 상태를 격리합니다. 각 액터나 고루틴은 독립적인 상태를 가지며, 통신은 명시적인 메시지 전달로 이루어집니다. 이는 I/O 바운드 작업에서 효율적입니다. I/O 대기 중 스레드가 차단되지 않고 다른 작업을 수행할 수 있어 컨텍스트 스위칭 오버헤드를 줄이고 시스템 자원을 더 잘 활용할 수 있습니다.

트레이드오프로는 스레드 기반 모델은 구현이 직관적일 수 있으나 데드락, 레이스 컨디션 같은 복잡한 동기화 이슈에 취약합니다. 비동기 모델은 상태 격리로 안전성을 높이지만, 메시지 전달 방식의 설계와 디버깅이 더 복잡할 수 있습니다.

#공유 메모리#Actor 모델#I/O 바운드#CPU 바운드#컨텍스트 스위칭

이 질문 단독 페이지 →

함께 보면 좋은 CS 기초 면접 질문

CS 기초 면접 질문 전체 보기 → 전체 카테고리

보유한 동시성 / 멀티스레딩 질문은 이게 전부가 아닙니다

패스잇 앱에는 직무별 면접 질문 수천 개와 모범답안이 담겨 있습니다. AI 모의면접으로 직접 답하고, 약점을 분석받아 보세요.