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