Java에서 request mapping은 Spring Framework에서 제공하는 기능 중 하나로, 클라이언트의 요청에 따라 적절한 메소드를 호출하고 그 결과를 반환하는 것을 말합니다. 이때, 멀티스레드를 이용하면 여러 클라이언트의 요청을 동시에 처리할 수 있습니다.
위 주제의 고민은 서버스펙 및 물리적 인프라 스팩을 적절하게 프로비저닝하여 소프트웨어의 성능을 유지 및 햫상시킬 수 있으나, 소프트웨어 로직 측면에서도 성능을 개선할 수 있는 포인트가 있지 않을까 하는 의문에서 시작되었습니다.
JAVA에서 멀티스레드 구현하기
다음은 Spring Framework에서 Request Mapping을 이용한 멀티스레드 처리를 위한 예시 코드입니다. 이 코드는 클라이언트로부터 요청이 들어오면, 각 요청에 대해 별도의 스레드를 생성하고, 해당 스레드에서 요청을 처리하는 방식으로 동작합니다.
@Controller
public class RequestController {
@Autowired
private ExecutorService executorService;
@RequestMapping("/processRequest")
@ResponseBody
public String processRequest() {
executorService.submit(new RequestHandler());
return "Request processing has started.";
}
private class RequestHandler implements Runnable {
@Override
public void run() {
// 요청 처리 로직 작성
}
}
}
위 코드에서 processRequest
메소드는 클라이언트로부터 요청이 들어오면 실행되며, **executorService
**를 이용하여 새로운 스레드를 생성하고, 해당 스레드에서 RequestHandler
클래스의 run
메소드를 실행합니다. RequestHandler
클래스는 Runnable
인터페이스를 구현하여, 별도의 스레드에서 실행될 수 있는 클래스입니다. 따라서, 각 요청에 대해 별도의 스레드가 생성되고, 해당 스레드에서 요청 처리 로직이 실행됩니다.
위 코드에서 **executorService
**는 스레드 풀을 구현한 객체로, submit
메소드를 이용하여 새로운 스레드를 생성하고, 해당 스레드에서 실행될 작업을 지정할 수 있습니다. 이를 통해, 스레드 생성 및 관리를 쉽게 할 수 있습니다.
Session을 체크하여 선행스레드 Lock
다음은 특정 사용자의 세션을 체크해서 현재 실행중인 스레드가 있다면 별도의 스레드를 만들지 않고 앞의 스레드를 처리되기까지 기다렸다가 스레드를 생성하는 코드 예시입니다.
@Controller
public class RequestController {
private final Object lock = new Object();
private Map<String, Thread> threadMap = new ConcurrentHashMap<>();
@RequestMapping("/processRequest")
@ResponseBody
public String processRequest(HttpServletRequest request) {
String sessionId = request.getSession().getId();
synchronized (lock) {
if (threadMap.containsKey(sessionId)) {
Thread thread = threadMap.get(sessionId);
if (thread.isAlive()) {
try {
thread.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
Thread newThread = new Thread(new RequestHandler(sessionId));
threadMap.put(sessionId, newThread);
newThread.start();
}
return "Request processing has started.";
}
private class RequestHandler implements Runnable {
private final String sessionId;
public RequestHandler(String sessionId) {
this.sessionId = sessionId;
}
@Override
public void run() {
// 요청 처리 로직 작성
synchronized (lock) {
threadMap.remove(sessionId);
}
}
}
}
위 코드에서, processRequest
메소드는 클라이언트로부터 요청이 들어오면, 현재 실행 중인 스레드가 있는지 확인하고, 있다면 해당 스레드가 종료될 때까지 기다린 후 새로운 스레드를 생성하여 요청 처리를 진행합니다.
**threadMap
**은 각 세션에 대응하는 스레드 객체를 저장하기 위한 자료구조로, **ConcurrentHashMap
**을 이용하여 스레드 안전성을 보장합니다. **lock
**은 동기화를 위한 객체로, 여러 스레드가 동시에 **threadMap
**에 접근하여 수정하는 것을 방지하기 위해 사용됩니다.
RequestHandler
클래스는 각 요청에 대해 별도의 스레드에서 실행될 클래스로, 생성자에서는 현재 요청에 대한 세션 ID를 받아 저장합니다. run
메소드에서는 요청 처리 로직을 작성하며, 처리가 완료되면 **threadMap
**에서 해당 세션 ID에 대응하는 스레드 객체를 제거합니다.