본문 바로가기
네이버클라우드/JAVA 웹 프로그래밍

JAVA 38일차 (2023-07-14) 자바 프로그래밍_스레드 재사용하기 : 스레드풀(thread pool) 구현_개인프로젝트 - 마트 관리 시스템

by prometedor 2023. 7. 16.
## 44. 스레드 재사용하기 : 스레드풀(thread pool) 구현

- Pooling 기법을 활용하여 스레드를 재사용하는 방법
- GoF의 FlyWeight 디자인 패턴(풀링 기법)을 적용하여 스레드풀을 구현하는 방법

 

 

 

ㄴ report-server 의 bitcamp.util 패키지에 TreadPool 이라는 이름의 클래스를 생성

 

ㄴ report-server 의 bitcamp.util 패키지에 ResourcePool 이라는 이름의 interface 를 생성

 

ResourcePool.java

 

ㄴ report-server 의 bitcamp.util 패키지에 ManagedThread 라는 이름의 클래스를 생성

 

ManagedThread.java

ㄴ ManagedThread 클래스는 Thread 를 상속 받도록 함

 

ThreadPool.java

ㄴ ThreadPool 클래스는 bitcamp.util 패키지에 있는 ResourcePool<ManagedThread>을 구현함

ㄴ ThreadPool 클래스는 ManagedThread 객체의 리스트를 유지함

 

ThreadPool.java

ㄴ getResource() 메서드를 오버라이딩 함

 

ThreadPool.java

ㄴ returnResource 메서드를 오버라이딩 함

 

ThreadPool.java

ㄴ getResource 메서드는 리스트가 비어있으면 새로운 ManagedThread 객체를 생성하여 반환하고, 그렇지 않은 경우 리스트에서 첫 번째 ManagedThread 객체를 제거하고 반환함

ㄴ returnResource 메서드는 전달된 ManagedThread 객체를 리스트에 추가함

ManagedThread.java


ㄴ ResourcePool<ManagedThread>을 가리키는 pool 멤버 변수를 가지고 있음
ㄴ ManagedThread 클래스는 Thread를 확장하여 스레드 동작을 수행할 수 있음

ㄴ 생성자에서는 ResourcePool<ManagedThread>을 인자로 받아 pool 멤버 변수에 할당함

     => 이를 통해 ManagedThread가 속한 스레드 풀을 알 수 있음

 

ㄴ report-server 의 bitcamp.util 패키지에 Job 이라는 이름의 interface 를 생성

 

Job.java

ㄴ execute 메서드를 규칙으로 정의

ㄴ Job 인터페이스는 execute()라는 하나의 메서드를 선언함

ㄴ 이 메서드는 작업의 실행 로직을 나타내며 매개변수를 받지 않고 반환값이 없음
ㄴ Job 인터페이스는 다른 클래스가 구현하여 특정 작업을 정의하는 데 사용됨

ㄴ Job 인터페이스를 구현함으로써 클래스는 execute() 메서드에 대한 자체 구현을 제공할 수 있으며, 이는 작업이 실행되어야 할 때 호출됨

 

ManagedThread.java

=>

ㄴ setJob 메서드는 Job 객체를 받아서 job 멤버 변수에 할당하고, notify를 호출하여 스레드를 깨우도록 함

ㄴ run 메서드에서는 무한 루프를 실행하며, 스레드가 대기 상태로 들어갈 때마다 wait를 호출하여 대기하도록 함

ㄴ job 객체가 할당된 경우 해당 작업을 실행한 후, job을 초기화하고 스레드를 리소스 풀에 반환하도록 함

 

ThreadPool.java

ㄴ 새 스레드 생성될 경우 "새 스레드 생성!" 을 출력하도록 하여 확인

 

ThreadPool.java

ㄴ 기존 스레드가 리턴될 경우 " 기존 스레드 리턴!" 을 출력하도록 하여 확인

 

ServerApp.java

ㄴ 스레드를 리턴해줄 스레드풀 준비

 

ServerApp.java

ㄴ 클래스 이름을 RequestAgentThread => RequestProcessJob 으로 변경

     ㄴ Job 인터페이스를 구현하도록 함

ㄴ run => execute 로 변경

 

ServerApp.java

ㄴ threadPool.getResource()를 호출하여 스레드 풀에게 스레드 자원을 요청함

     ㄴ getResource() 메서드는 스레드 풀에서 사용 가능한 스레드를 가져오는 역할을 함
     ㄴ getResource() 메서드로부터 반환된 ManagedThread 객체를 t 변수에 할당합니다.
ㄴ t.start()를 호출하여 ManagedThread 객체를 시작함

     ㄴ start() 메서드는 해당 스레드의 run() 메서드를 실행하게 됨

 

ThreadPool.java

ㄴ getResource() 메서드는 스레드 풀에서 사용 가능한 스레드를 가져옴
ㄴ 스레드 풀의 리스트가 비어있는 경우, 새로운 ManagedThread 객체를 생성하고, start() 메서드를 호출하여 스레드를 시작하고 생성된 스레드를 반환함
ㄴ 스레드 풀의 리스트에 스레드가 있는 경우, 리스트에서 첫 번째 스레드를 제거하고 반환함
ㄴ returnResource() 메서드는 사용한 스레드를 스레드 풀에 반환하고 리스트에 스레드를 추가함
ㄴ 스레드 생성, 시작, 반환 등의 동작을 확인하기위해 각각 동작마다 내용 출력

ServerApp.java

ㄴ serverSocket.accept()를 호출하여 클라이언트의 소켓 연결을 기다고, 클라이언트가 연결되면 해당 클라이언트 소켓을 socket 변수에 할당함
ㄴ threadPool.getResource()를 호출하여 스레드 풀에게 스레드 자원을 요청하도록 함
    ㄴ getResource() 메서드로부터 반환된 ManagedThread 객체를 t 변수에 할당함
ㄴ t.setJob(new RequestProcessJob(socket))을 호출하여 ManagedThread 객체에 클라이언트 소켓을 처리할 작업(RequestProcessJob)을 할당함


=> 클라이언트의 소켓 연결이 수신되면 해당 소켓을 처리할 스레드를 스레드 풀에서 가져온 후 작업을 할당함

 

server 실행하여 확인

=>

서버

클라이언트

 

ManagedThread.java

ㄴ 스레드 번호를 추적하기 위한 추가적인 정적 변수 count와 각 스레드의 고유 식별자를 저장하는 인스턴스 변수 no 를 선언함

 

ManagedThread.java

ㄴ ManagedThread 객체가 생성될 때마다 no 를 1씩 증가시킴(count 변수 이용)

 

ManagedThread.java

ㄴ 스레드가 start 될 때마다 몇 번 스레드가 실행되는지 확인하기 위해 해당 코드 추가

 

ThreadPool.java

ㄴ 생성한 스레드가 바로 실행될 수 있도록 main 스레드가 잠시 잠들도록 해줌

 

익명 클래스로 만든 후 람다로 변경하기

ServerApp.java

=>

ServerApp.java

=>

ServerApp.java

=>

ServerApp.java

=>

ServerApp.java

=>

ServerApp.java

=>

ServerApp.java

=>

ServerApp.java

=>

ServerApp.java