본문 바로가기

공부/자료구조

실무에서는 Stack 클래스보다 Deque 인터페이스의 ArrayDeque를 스텍으로 쓰는 게 더 권장?

왜 Stack 클래스를 잘 안 쓰나?

1. Stack은 사실 Vector을 상속받은 "레거시" 클래스

public class Stack<E> extends Vector<E> {
  ...
}

 

Vector는 java 초창기(1.0)에 만들어진 클래스로, 지금은 거의 안 쓰인다. Stack이 이걸 상속받다 보니, 스택에는 필요 없는 기능들까지 전부 딸려온다. 스택은 원래 " 맨 위에서만 push/pop"하는게 정체성인데, Vector를 상속해서 get(index), add(index, value)처럼 스택 원칙을 깨는 기능도 다 열려버린다.

 

2. Vector는 내부적으로 동기화(Synchronized) 되어 있음

멀티스레드 환경에서 안전하라고 모든 메서드에 락(lock)이 걸려 있는데, 대부분의 경우 멀티스레드 동기화가 필요 없는데도 이 비용을 그냥 지불하게 된다. > 불필요한 성능 손해

 

3. ArrayDeque가 더 빠르고 깔끔

ArrayDeque (Array + Double Ended Queue)는 스택과 큐 둘 다로 쓸 수 있게 설계된 클래스로, 동기화 오버헤드가 없고 내부 구현도 더 효율적.

 

실제 Java 공식 문서 권장사항

 

 

정리

  Stack ArrayDeque
상속구조 Vector 상속(레거시) 독립적으로 설계
동기화 항상 동기화 (오버헤드 있음) 동기화 없음 (더 빠름)
스택 원칙 준수 꺠짐 (중간 삽입 가능) 지켜짐
실무권장 X O

 

여기서, 멀티쓰레드 환경에서는 Stack을 써도 되는지 궁금증이 생긴다.

 

결론으로는 멀티스레드 환경에서도 Stack을 쓰지 않는게 좋다.

Stack이 "동기화되어 있다"는 이유만으로 멀티스레드에 안전하다고 오해하기 쉬운데, 실제로는 그렇지 않다.

 

1. Stack의 동기화는 "메서드 하나하나"만 보호하지, "여러 동작의 조합"은 못 지켜줌

Stack<Integer> stack = new Stack();

// 스레드 A, B가 동시에 아래 코드를 실행한다고 하면
if (!stack.isEmpty()) { // 1.비어있는지 확인
   int value = stack.pop(); // 2. pop
}

 

isEmpty()도 동기화되어 있고 pop()도 동기화되어 있지만, 1과 2 사이에 다른 스레드가 끼어들 수 있다.

더보기

스레드 A : isEmpty() 확인 > false (원소 1개 있음)

스레드 B : isEmpty() 확인 > false (아직 A가 pop 안 했으니 여전히 1개)

스레드 A : pop() 실행 > 마지막 원소 꺼냄, 스택 이제 empty

스레드 B : pop() 실행 > EmptyStackException ! (이미 비었는데 또 꺼내려 함)

각 메서드 자체는 안전한데, 여러 메서드를 조합해서 쓰는 순간은 여전히 위험. 이걸 "복합 연산(compound operation)의 원자성이 깨진다"라고 표현한다.

 

2. 진짜 멀티스레드용 도구는 따로 존재

Java는 멀티스레드 환경을 위해 처음부터 이런 문제까지 고려해서 설계된 별도의 클래스들을 java.util.concurrent 패키지에 제공

import java.util.concurrent.ConcurrentLinkDeque;

Deque<Integer> stack = new ConcurrentLinkedDeque<>();
stack.push(10);
stack.push(20);
Integer value = stack.pop(); // 내부적으로 락 없이도 (lock-free) 안전하게 동작

 

또는 블로깅이 필요한 경우

import java.util.concurrent.LinkedBlockingDeque;

LinkedBlockingDeque<Integer> stack = new LinkBlockingDequeM<>();

 

이런 클래스들은 synchronized로 메서드 하나씩 잠그는 원시적인 방식이 아니라, CAS(Compare-And-Swap)같은 더 정교한 기법으로 동시성을 다뤄서 성능도 훨씬 좋고 실제로 안전.

상황 추천
싱글스레드(대부분의 일반 로직) ArrayDeque
멀티스레드 + 진짜 동시성 안전 필요 java.util.concurrent의 ConcurrentLinkDeque 등
Stack 클래스 거의 항상 비추천(레거시, 어중간하게 느리고 어중간하게만 안전)

 

LinkedBlockingDeque 란?

728x90

'공부 > 자료구조' 카테고리의 다른 글

락(lock)과 교착상태(Dead lock)  (0) 2026.08.29
Stack  (0) 2026.08.25
연결 리스트 (Linked List)  (0) 2026.08.24