simDev1234
심플하고 차분하게
simDev1234
전체 방문자
오늘
어제
  • 분류 전체보기
    • Computer Science
      • Basic Math
      • Data Structure
      • Algorithm
      • Database
      • OS
    • Language
      • Java
      • Kotlin
      • SQL
    • Framework
      • Spring
      • Orm&Mapper
      • 프로젝트로 스프링 이해하기
      • 스프링 라이브러리
    • Infra
      • Cloud
      • Docker
      • Redis
      • AWS, Azure
      • Device
    • Etc
      • CleanCoding
    • Git,Github

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 컨트롤러
  • 자바프로그램
  • 자바메모리구조
  • scanner #next() #nextLine()
  • 자바프로그래밍
  • 참조타입
  • null
  • controllerTest
  • 404
  • 참조변수
  • JVM메모리구조
  • 스프링
  • 자바

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
simDev1234

심플하고 차분하게

Framework/스프링 라이브러리

[Scheduler] 스케줄러 사용하기 (feat. 쓰레드, 쓰레드풀)

2022. 11. 11. 13:47

|  Scheduler

- 스프링에서 일정 주기마다 특정 작업을 수행할 수 있도록 하는 기능

- 주기 설정

fixedDelay 작업 완료시점을 기준으로 일정시간 지연 후 반복
fixedRate 작업 시작지점을 기준으로 일정시간 지연 후 방복
cron 정규식 표현

- Cron 표현식

(1) 사용법 

// 초/분/시/일/월/요일/연도(생략가능)

0 0 0 * * *   <-- 매일 00시에 
0/10 * * * *  <-- 10초마다
0 0/5 * * *   <-- 5분마다
0 0 14 * * *  <-- 매일 오후 2시
0 0 2 ? 7 MON-WEB <-- 매년 7월 월-수 2시 00분 00초

(2) 범위

초 0 - 59
분 0 - 59
시 0 - 23
일 1 - 31
월 1 ‒ 12 || JAN - DEC

요일 0 - 6 || SUN - SAT

연도 1970 - 2099

(3) 특수기호 의미

*  : 모든 수
? : 조건 없음(날짜와 요일에만 사용)
-  : 범위(기간) 지정
,  : 특정 여러 시간 지정
/  : 시작 시간과 반복 간격
L : 지정할 수 있는 범위의 마지막 값 (날짜와 요일에만 사용)

 

|  기본 사용법

1. @SpringBootApplication에 @EnableScheduling을 추가한다.

@SpringBootApplication
@EnableScheduling
public class BaedanguemApplication {

    public static void main(String[] args) {
        SpringApplication.run(BaedanguemApplication.class, args);

    }

}

2. 스케줄러를 통해 제어해야하는 기능에 @Scheduled를 추가한다.

@Component
public class TestScheduler{

    @Scheduled(cron = "0 0 0 * * *")
    public void test(){
    	// 원하는 기능 삽입
    }

}

3. 스케줄러의 주기를 별도로 관리하고 싶을 경우

(1) application.yml에 cron 표현식을 작성하여 사용할 수도 있다.

// application.yml
scheduler:
   scrap:
      yahoo: "0 0 0 * * *"

(2) SpEL을 통해 @Scheduled에 속성값을 넣어주기

@Component
public class TestScheduler{

    @Scheduled(cron = "${scheduler.scrap.yahoo}")
    public void test(){
    	// 원하는 기능 삽입
    }

}

 

|  쓰레드 개념

- 멀티 쓰레드란? 한 프로세스가 여러 스레드로 동시에 여러 작업을 수행하는 것을 말한다.

  * 하나의 프로세스 안에 여러 개의 쓰레드가 공유 자원을 두고 소통한다.

  * 동기화 이슈 : 작업 사이에 실행 시기를 맞추는 걸 동기화라고 한다.

                           여러 쓰레드가 동일 자원에 접근할 때 동기화 이슈, 곧, 작업이 꼬이는 이슈가 발생한다.

  * 동기화 이슈 해결 방안 : Mutual Exclusion (상호 배제) 

     * 뮤텍스와 세마포어 : 뮤텍스는 하나하나씩 공유 자원에 접근하게 하는 거고, 

                                        세마포어는 접근 갯수를 정하는 걸 말한다.

  * 교착상태(Deadlock)  : 쓰레드들이 서로 상대방의 작업을 기다리면서 무한 대기 상태에 빠지는 것

    * 조건 : 상호 배제, 점유 대기, 비선점, 순환대기

  * 기아상태(Starvation) : 특정 프로세스의 우선순위가 낮아 원하는 자원을 할당 받지 못하는 상태

- 쓰레드의 다섯가지 상태

  (1) new : 탄생

  (2) ready : 준비 (=runnable)

  (3) running : 실행

  (4) blocked/waiting : 일시정지(봉쇄/대기)

  (5) exit : 종료 (=terminated)

- 자바에서 쓰레드를 일시정지 시키기

// 쓰레드 일시정지 
Thread.sleep(1000); // 1초간 쓰레드 일시정지 후 깨어남

// 쓰레드 wait()와 다르다
Thread.wait(1000);  // 1초간 쓰레드 대기하기 <- 멀티쓰레드 환경에서 쓰레드간 통신 위해 사용
                                           // ㄴ notify() 또는 notifyAll()를 호출할 때까지 
                                           //    계속 대기하고 있는다.

- IntertuptedException : 인터럽트를 받은 스레드가 blocking 될 수 있는 메소드를 실행할 때 발생

- 자바에서 쓰레드를 종료시켜야할 때

   * 자바에서 쓰레드를 사용할 땐, stop() 을 사용하지 않는다 -- deprecated되었다.

   * 이유는, 종료시 자원들이 불완전한 상태로 남겨지지 때문이다. 

   * 대신 interrupt() 메소드를 통해 intteruptedException을 발생시켜 쓰레드를 종료한다.

try {
    Thread.sleep(3000); // 3 seconds
} catch (InterruptedException e) { // 인터럽트를 받는 스레드가 blocking 될 수 있는 메소드를 실행할 때 발생
    e.printStackTrace();
    Thread.currentThread().interrupt();
}

 

|  스프링의 Scheduler 쓰레드 동작방식

- @Scheduled가 붙은 여러개의 메소드들이 있다고 가정할 때, 스프링을 실행하면

  (1) main 쓰레드가 작동하고

  (2) Scheduling 쓰레드가 별도로 하나 작동한다.

- 쓰레드풀을 통해 멀티 쓰레드 환경을 만들지 않았다면, 다수의 @Scheduled 메소드들은 하나의 쓰레드 안에서 작동한다.

- 아래와 같이 메인 함수와, 스케줄러 함수들을 작동시켰을 때에 결과를 보면, 

  여러 개의 스케줄링 메소드가 하나의 쓰레드에서 실행이되면서,

  의도한 스케줄링 시간에 맞지 않게 작동이 되는 걸 볼 수 있다.

@SpringBootApplication
@EnableJpaRepositories("com.example.petbutler.persist")
@EnableTransactionManagement
@EnableScheduling
public class PetbutlerApplication {

 public static void main(String[] args) {
  SpringApplication.run(PetbutlerApplication.class, args);
  System.out.println(Thread.currentThread().getName() + "-> MAIN");
 }

}
@Configuration
public class SchedulerConfig {

  // 1초 후 10초 동안 일시정지
  @Scheduled(fixedDelay = 1000)
  public void test1(){

    try {
      System.out.println(Thread.currentThread().getName() + "-> 테스트1");
      Thread.sleep(10000);
    } catch (InterruptedException e) {
      e.printStackTrace();
      Thread.interrupted();
    }

  }

  // 1초 후 1초 동안 일시정지
  @Scheduled(fixedDelay = 1000)
  public void test2(){

    try {
      System.out.println(Thread.currentThread().getName() + "-> 테스트2");
      Thread.sleep(1000);
    } catch (InterruptedException e) {
      e.printStackTrace();
      Thread.interrupted();
    }

  }

}

>> 결과

- 테스트1이 실행된 후 10초가 지난 후에야 테스트2가 작동하며, 이것이 반복된다.

scheduling-1-> 테스트2
2022-11-11 13:28:05.641 DEBUG 23980 --- [           main] ySourcesPropertyResolver$DefaultResolver : Found key 'spring.liveBeansView.mbeanDomain' in PropertySource 'systemProperties' with value of type String
2022-11-11 13:28:05.643  INFO 23980 --- [           main] c.e.petbutler.PetbutlerApplication       : Started PetbutlerApplication in 17.004 seconds (JVM running for 20.012)
2022-11-11 13:28:05.645 DEBUG 23980 --- [           main] o.s.b.a.ApplicationAvailabilityBean      : Application availability state LivenessState changed to CORRECT
2022-11-11 13:28:05.647 DEBUG 23980 --- [           main] o.s.b.a.ApplicationAvailabilityBean      : Application availability state ReadinessState changed to ACCEPTING_TRAFFIC
main-> MAIN
scheduling-1-> 테스트1
scheduling-1-> 테스트2
scheduling-1-> 테스트1
scheduling-1-> 테스트2
scheduling-1-> 테스트1
scheduling-1-> 테스트2
scheduling-1-> 테스트1
scheduling-1-> 테스트2
scheduling-1-> 테스트1

 

|  Thread Pool 개념

- 여러 개의 쓰레드를 유지/관리하기 위해서 사용한다.

- 미리 설정해준 크기만큼 쓰레드들을 만들어 두고, 해당 쓰레드들을 계속해 재사용할 수 있게 한다.

- Thread Pool의 적정 사이즈는?

  * 너무 적은, 너무 많은 Thread Pool을 만들지 않는 것이 필요하다.

  * 정확한 공식이 있는 것은 아니나 일반적으로 아래와 같이 지정할 경우 최적화하여 사용할 수 있다.

- CPU 처리가 많은 경우 : CPU 코어 갯수 N + 1    *연산작업
- I/O 작업이 많은 경우    : CPU 코어 갯수 N x 2    *I/O작업(=입출력작업)은 블로킹이 많다.

  * rf. I/O 란? I/O란 하드웨어 장치를 통한 입출력 정보를 컴퓨터에서 구동 중인 어플리케이션에서 컨트롤하고자 할 때 사용하는 일종의 인터페이스

 

|  스프링 스케줄러에서 ThreadPool를 사용하기

1. SchedulingConfigurer를 구현한 설정 클래스를 만든다.

2. configureTask(ScheduluedTaskRegistrar taskRegistrar) 메소드를 Override한다.

3. 메소드 안에서 ThreadPoolTaskScheduler 인스턴스를 생성한다.

4. ThreadPoolTaskScheduler에 쓰레드 갯수를 setting 하고 initialize(초기화)한다.

    * Runtime.getRuntime().availableProcessors() 를 통해 CPU의 코어 갯수를 알아낼 수 있다.

5. ThreadPoolTaskScheduler를 매개변수인 taskRegistrar에 넣는다.

// 쓰레드 풀 설정
@Configuration
public class SchedulerConfig implements SchedulingConfigurer {

    //   쓰레드 풀 갯수 설정 예시
    //   - CPU 처리가 많은 경우 CPU 코어 갯수 N + 1
    //   - I/O 작업이 많은 경우 CPU 코어 갯수 N x 2

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {

        ThreadPoolTaskScheduler threadPool = new ThreadPoolTaskScheduler();

        int n = Runtime.getRuntime().availableProcessors(); // core 갯수
        threadPool.setPoolSize(n + 1); // 쓰레드 풀 갯수 설정
        threadPool.initialize();       // 쓰레드 풀 초기화

        taskRegistrar.setTaskScheduler(threadPool); // 스케줄러에서 쓰레드풀 사용

    }

}

 

 

[참고 및 출처]

부트캠프 수업내용 정리

쓰레드 관련 

https://darrengwon.tistory.com/763

https://gold-dragon.tistory.com/263

https://velog.io/@jsj3282/Thread%EC%9D%98-%EC%83%81%ED%83%9C#1-%EC%93%B0%EB%A0%88%EB%93%9C%EB%9E%80

interrupt https://cornswrold.tistory.com/190

I/O는 어떻게 처리될까 https://chelseafandev.github.io/2021/07/13/os-io-system/

'Framework > 스프링 라이브러리' 카테고리의 다른 글

[Scraping] Jsoup으로 스크래핑하기  (0) 2022.12.13
[스프링 시큐러티] JWT 토큰 + 스프링 시큐러티  (0) 2022.11.18
[스프링 시큐러티] 스프링 시큐러티 자료 모음 (수정중)  (0) 2022.10.29
[TEST] TDD 방식에 대한 자료 모음 (수정중)  (0) 2022.10.28
[JSON 파싱] ObjectMapper, Simple-json  (0) 2022.10.24
    'Framework/스프링 라이브러리' 카테고리의 다른 글
    • [Scraping] Jsoup으로 스크래핑하기
    • [스프링 시큐러티] JWT 토큰 + 스프링 시큐러티
    • [스프링 시큐러티] 스프링 시큐러티 자료 모음 (수정중)
    • [TEST] TDD 방식에 대한 자료 모음 (수정중)
    simDev1234
    simDev1234
    TIL용 블로그. * 저작권 이슈가 있는 부분이 있다면 댓글 부탁드립니다.

    티스토리툴바