java의 멀티스레드 부분을 공부하면서 다음과 같은 궁금증이 생겼다.
스프링부트에서 restTemplate으로 요청을 보낸상태(응답은 받지 않은 상태)인경우
스프링부트에서 RestTemplate으로 요청을 보낸 스레드의 상태는 어떤 상태일까?
그래서 다음과 같은 코드를 작성해 보았다.
@RequestMapping("/rest-template-test")
@RestController
public class RestTemplateTestController {
@GetMapping("/request")
public Map getRequest() throws InterruptedException {
System.out.println("request receive");
LocalDateTime requestTime = LocalDateTime.now();
Thread.sleep(2000);
LocalDateTime responseTime = LocalDateTime.now();
System.out.println("request send");
Map responseMap = Map.of("requestTime", requestTime, "responseTime", responseTime);
return responseMap;
}
@GetMapping("/test")
public void getResponse() throws InterruptedException {
Thread requestThread = new Thread(()-> {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
RestTemplate restTemplate = new RestTemplate();
Map a = restTemplate.getForObject("http://localhost:8080/rest-template-test/request", Map.class);
});
requestThread.setName("requestThread");
requestThread.start();
for (int i=0; i<10; i++) {
System.out.println("reqeustThread state: " + requestThread.getState());
Thread.sleep(300);
}
}
}
먼저 위의 getRequest메서드는 GET요청을 받으면 2초간 스레드를 멈추고 대기한 후 응답하는 메서드이다.
중요한 부분은 아랫부분의 getResponse메서드인데, 위의 getRequest메서드로 요청을 보내는 RestTemplate요청을 보내는 스레드를 설정하고 0.3초 간격으로 스레드의 상태를 확인하였다.
내가 예상했던 결과는 요청을 받기 전까지 스레드의 상태가 WAITING 또는 BLOCKED 상태일 것으로 예상했었다. 나름 합리적이라고 생각했던 이유는 요청을 보내고 얼마나 오랬동안 기다려야 할지 모르니 그동안 스레드를 점유하는 것은 리소스의 낭비라고 생각했기 때문이다.
하지만 실제로 실행해본 결과는 다음과 같이 나타났다.
요청을 보낸 이후로도 계속 RUNNABLE 상태를 유지하고 있는 것이다.
그래서 스레드 덤프를 통해 어느 부분에서 스레드를 잡고 있는지 확인해 봤다
SocketDispatcher.read0 작업이 스레드를 잡고 있는 걸 확인했다.
내 예상과 다른 결과가 나왔기 때문에 조금 구글링을 해 보았는데, 다음과 같은 결론을 얻었다.
HTTP-커넥션과 연관되어 있는 부분인데 간단하게 HTTP 요청은 다음과 같이 일어난다.
중요한 것은 서버가 요청을 읽고 처리하는동안 클라이언트가 Socket.read()를 통해 응답을 기다린다는 것이다. 이 과정에서 스레드가 RUNNABLE상태로 계속 대기하는 것이 확인되는 것이다.
생각해 보면 내 예상이 틀릴수 밖에 없었던게 결국은 요청을 보낸 쪽에서도 스레드는 돌고있어야 돌아오는 응답을 읽을 수 있을텐데 잘못 생각했다는 걸 깨달았다.
항상 서버 입장에서 생각하다가 반대로 클라이언트 입장에서 생각해 볼수 있었던 시간이었고 또, 알게된건 이번에도 NIO네트워크스트림이 관련되었기 때문에 빨리 NIO에 대해 공부를 해놔야겠다!…