Java 미드레벨 종합 기술면접
새 면접Q. Java의 ThreadLocal은 무엇이며 어떤 원리로 동작하는지 설명해주세요. 또한 ThreadLocal을 사용할 때 메모리 누수가 발생할 수 있는 상황과 이를 방지하기 위한 방법을 설명해주세요.
ThreadLocal은 각 스레드마다 독립적인 변수 공간을 제공하는 클래스로, 내부적으로 Thread 객체의 threadLocals 맵에 현재 ThreadLocal 인스턴스를 키로 하여 값을 저장합니다. 스레드 풀 환경에서 스레드가 재사용될 때 ThreadLocal 값이 제거되지 않으면 메모리 누수가 발생할 수 있으며, 반드시 사용 후 remove() 메서드를 호출하거나 try-finally 블록으로 정리해야 합니다. 특히 웹 애플리케이션에서 요청 컨텍스트를 저장할 때 주의가 필요하며, Spring Security의 SecurityContextHolder가 대표적인 사용 예시입니다.
- • 각 스레드마다 독립적인 변수 공간 제공, Thread 객체 내부의 ThreadLocalMap에 저장
- • 스레드 풀 환경에서 스레드 재사용 시 이전 값이 남아있어 메모리 누수 발생 가능
- • 반드시 사용 후 remove() 호출로 정리 필요, try-finally 패턴 권장
- • 요청 컨텍스트, 트랜잭션 정보, 사용자 인증 정보 저장 등에 활용
InheritableThreadLocal은 일반 ThreadLocal과 어떻게 다르며, 실무에서 사용 시 주의할 점은 무엇인가요?
Q. Proxy 패턴과 Decorator 패턴의 구조적 유사성과 의도상의 차이점을 설명하고, Java에서 Dynamic Proxy를 활용한 실무 사례를 제시해주세요.
Proxy 패턴은 실제 객체에 대한 접근을 제어하거나 지연시키는 것이 목적이며, Decorator 패턴은 객체에 동적으로 기능을 추가하는 것이 목적입니다. 구조적으로는 둘 다 원본 객체를 감싸는 래퍼 형태이지만, Proxy는 접근 제어, 지연 로딩, 캐싱 등을 담당하고 Decorator는 기능 확장을 담당합니다. Java의 JDK Dynamic Proxy는 인터페이스 기반으로 런타임에 프록시 객체를 생성하며, Spring AOP, Hibernate의 Lazy Loading, 트랜잭션 관리 등에서 활용됩니다.
- • Proxy는 접근 제어 목적, Decorator는 기능 추가 목적
- • Proxy는 원본 객체 생성을 지연시키거나 숨길 수 있지만, Decorator는 항상 실제 객체 필요
- • JDK Dynamic Proxy는 InvocationHandler를 통해 런타임에 프록시 생성
- • Spring AOP, Lazy Loading, 원격 프록시, 보안 프록시 등 실무 활용 다양
CGLIB Proxy와 JDK Dynamic Proxy의 차이점은 무엇이며, 각각 어떤 상황에서 사용되나요?
Q. Java 애플리케이션에서 CPU 사용률이 비정상적으로 높게 나타날 때, 어떤 순서와 도구를 사용하여 원인을 분석하고 해결하시겠습니까? 스레드 덤프 분석 방법과 함께 설명해주세요.
먼저 top 또는 ps 명령어로 CPU를 많이 사용하는 Java 프로세스를 식별하고, top -H -p [PID] 명령으로 해당 프로세스 내에서 CPU를 많이 사용하는 스레드 ID를 확인합니다. 스레드 ID를 16진수로 변환한 후, jstack [PID]로 스레드 덤프를 생성하여 해당 nid를 가진 스레드의 스택 트레이스를 분석합니다. 무한 루프, 비효율적인 정규표현식, 과도한 GC, 동기화 대기, 데드락 등이 주요 원인이며, 스레드 상태(RUNNABLE, BLOCKED, WAITING)와 락 정보를 함께 확인하여 근본 원인을 파악합니다.
- • top -H -p로 스레드별 CPU 사용률 확인 후 스레드 ID를 16진수로 변환
- • jstack으로 스레드 덤프 생성하여 nid로 해당 스레드의 스택 트레이스 분석
- • 무한 루프, 정규표현식, GC, 동기화 대기, 데드락 등 원인 파악
- • 여러 번 덤프를 떠서 패턴 분석, VisualVM이나 JProfiler 같은 프로파일러 활용 가능
CPU 사용률은 정상인데 애플리케이션 응답이 느린 경우는 어떻게 분석하시겠습니까?
Q. 마이크로서비스 아키텍처에서 분산 트랜잭션을 처리하기 위한 Saga 패턴의 Orchestration 방식과 Choreography 방식의 차이점을 설명하고, 각 방식의 장단점과 실무 적용 시 고려사항을 제시해주세요.
Orchestration 방식은 중앙의 오케스트레이터가 모든 서비스 호출 순서와 보상 트랜잭션을 관리하며, Choreography 방식은 각 서비스가 이벤트를 발행하고 구독하여 자율적으로 처리합니다. Orchestration은 흐름 파악이 쉽고 중앙 집중식 제어가 가능하지만 단일 장애점이 될 수 있으며, Choreography는 서비스 간 결합도가 낮지만 전체 흐름 파악이 어렵고 디버깅이 복잡합니다. 실무에서는 비즈니스 로직 복잡도, 서비스 개수, 팀 구조, 모니터링 요구사항 등을 고려하여 선택하며, 주문-결제-배송 같은 명확한 순서가 있는 경우 Orchestration이, 느슨한 결합이 중요한 경우 Choreography가 적합합니다.
- • Orchestration: 중앙 오케스트레이터가 모든 흐름 제어, 명확한 순서 관리
- • Choreography: 이벤트 기반으로 각 서비스가 자율적으로 반응, 낮은 결합도
- • Orchestration은 복잡한 워크플로우에 적합하나 SPOF 가능성, Choreography는 확장성 좋으나 디버깅 어려움
- • 보상 트랜잭션 설계, 멱등성 보장, 이벤트 순서 보장, 모니터링 전략 필수
Saga 패턴에서 보상 트랜잭션이 실패하는 경우는 어떻게 처리해야 하나요?
Q. Optional을 사용할 때 흔히 발생하는 안티패턴들을 설명하고, Optional을 올바르게 사용하기 위한 베스트 프랙티스를 제시해주세요. 특히 메서드 파라미터로 Optional을 사용하는 것이 권장되지 않는 이유는 무엇인가요?
대표적인 안티패턴으로는 Optional.get()을 바로 호출하여 NoSuchElementException 발생 가능성을 만들거나, isPresent() 체크 후 get()을 호출하는 것으로 null 체크와 다를 바 없는 코드를 작성하는 것입니다. Optional은 반환 타입으로만 사용하고 필드나 파라미터로는 사용하지 않으며, orElse 대신 orElseGet으로 불필요한 객체 생성을 방지하고, map/flatMap/filter 등의 함수형 메서드를 활용해야 합니다. 메서드 파라미터로 Optional을 사용하면 호출자가 Optional.of()로 감싸야 하는 번거로움이 생기고, 오버로딩이나 빌더 패턴으로 더 명확하게 표현할 수 있습니다.
- • Optional.get() 직접 호출 금지, isPresent() 후 get() 대신 orElse/orElseGet/orElseThrow 사용
- • 반환 타입으로만 사용, 필드/파라미터/컬렉션 요소로 사용 지양
- • orElse는 항상 평가되므로 orElseGet 사용 권장, map/flatMap으로 함수형 체이닝
- • 메서드 파라미터는 오버로딩이나 빌더 패턴으로 선택적 값 표현
Optional을 컬렉션에 담는 것이 권장되지 않는 이유와, 대신 사용할 수 있는 방법은 무엇인가요?
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!