Skip to Content
공부백엔드Servlet과 웹 서버7. Servlet과 Multi-Thread

Servlet과 Multi-Thread

Servlet의 특징 돌아보기

  • Servlet은 Multi Thread에 의해 공유됨

    • Servlet은 공유 자원으로 Thread Safe 하지 않음
    • Servlet이 상태 정보를 가지면 데이터 훼손 문제가 발생할 수 있음
  • 데이터 보호를 위해 synchronized 키워드 사용 → 한 번에 하나씩

    • synchronized를 통해 동기화 시키면 제대로 성능을 발휘할 수 없음

가급적 Servlet에는 멤버 변수를 통해 상태를 관리하지 않는다.

Multi Thread와 공유 자원 문제

하나의 Servlet 객체만 생성하며 멀티스레딩을 지원하여 동시 요청 처리가 가능하다. 하지만 이로 인한 문제가 발생할 수 있다.

위험한 코드 예시

UnsafeServlet.java
@WebServlet("/unsafe") public class UnsafeServlet extends HttpServlet { // 문제: 모든 사용자가 이 변수를 공유함 private int count = 0; // 여러 스레드가 동시에 수정하면 부정확 @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 동시에 여러 명이 접속하면 count가 정확하지 않음 count++; response.getWriter().println("방문자 수: " + count); } }

안전한 코드 작성

SafeServlet.java
@WebServlet("/safe") public class SafeServlet extends HttpServlet { // 멤버 변수 사용하지 않음! @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 로컬 변수는 각 스레드마다 독립적이므로 안전 int localCount = 0; localCount++; // 안전 String name = request.getParameter("name"); response.getWriter().println("처리 완료: " + name); } }

임계 구역 (Critical Section)

여러 스레드가 동시에 접근하면 안 되는 영역

동기화 기법

  • 뮤텍스 (Mutex): 임계 구역에 들어갈 수 있는 통로가 단 하나

    • 자리가 하나뿐인 화장실과 열쇠 하나
    • Java의 synchronized 키워드
  • 세마포어 (Semaphore): 임계 구역에 들어갈 수 있는 통로가 여러 개

    • 자리가 여러 개인 유료 주차장과 주차권
    • Connection Pool 등에서 사용

synchronized 사용 예시

SynchronizedExample.java
@WebServlet("/sync") public class SynchronizedServlet extends HttpServlet { private int count = 0; @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // synchronized로 동기화 - 한 번에 하나씩만 실행 synchronized(this) { count++; } // 하지만 성능이 떨어지므로 권장하지 않음! response.getWriter().println("카운트: " + count); } }

Thread-Safe한 대안

필요한 경우 Thread-Safe한 클래스 사용:

ThreadSafeExample.java
@WebServlet("/atomic") public class AtomicServlet extends HttpServlet { // Thread-Safe한 AtomicInteger 사용 private final AtomicInteger counter = new AtomicInteger(0); @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 안전한 증가 연산 int count = counter.incrementAndGet(); response.getWriter().println("안전한 카운트: " + count); } }

정리

  • Servlet은 하나의 인스턴스를 여러 스레드가 공유
  • 멤버 변수 사용 시 Thread Safety 문제 발생
  • 가능한 로컬 변수만 사용
  • 꼭 필요한 경우 Thread-Safe한 클래스 사용
  • synchronized는 성능 문제로 권장하지 않음
Last updated on