[Spring] @Scheduled 사용
2021. 12. 6. 17:12ㆍ개발노트
특정 기간, 원하는 주기에 따라 작업을 실행하기 위해 @Scheduled 가 사용된다.
@Scheduled 를 사용하기 위해서는 관련 클래스에 @EnableScheduling 을 추가해야한다.
@Scheduled 가 부텨되는 메서드는 파라미터를 가질 수 없고 반드시 void 리턴 타입이어야 하며
아래 세가지 작업을 수행 할 수 있다.
- fixedDelay: 이전 작업이 끝난 후 동작
- fixedRate: 이전 작업이 끝나는 것과 별개로 일정한 시간 간격으로 실행
- cron: 크론 주기에 따라 실행
cron
@EnableScheduling
@Component
public class Scheduler {
@Scheduled(cron = "1 * * * * *") // 1분 주기
public void cronJob() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
Date now = new Date();
String strDate = sdf.format(now);
System.out.println("strDate = " + strDate);
}
}
@EnableScheduling 사용으로 스프링에게 @Scheduled 사용을 알리고 위와 같이 크론 주기에 따라 코드를 실행 할 수 있다.
// OutPut
strDate = 2021-12-07 14:08:01.002
strDate = 2021-12-07 14:09:01.003
fixedDelay
@EnableScheduling
@Component
public class Scheduler {
@Scheduled(fixedDelay = 1000) // 작업 후 1초 후 실행
public void fixedDelayJob() throws InterruptedException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
Date now = new Date();
String strDate = sdf.format(now);
System.out.println("FixedDelayJob = " + strDate);
System.out.println(Thread.currentThread().getName());
Thread.sleep(4000);
}
}
4초 동안 sleep 하기 때문에 5초 후에 다음 작업이 실행된다.
// OutPut
FixedDelayJob = 2021-12-07 14:06:52.925
scheduling-1
FixedDelayJob = 2021-12-07 14:06:57.927
scheduling-1
FixedDelayJob = 2021-12-07 14:07:02.931
scheduling-1
fixedRate
@EnableScheduling
@Component
public class Scheduler {
@Scheduled(fixedRate = 1000) // 1초 간격 실행
public void fixedRateJob() throws InterruptedException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
Date now = new Date();
String strDate = sdf.format(now);
System.out.println("FixedDelayJob = " + strDate);
System.out.println(Thread.currentThread().getName());
Thread.sleep(2000);
}
}
2초 동안 sleep 하지만 작업이 시작된 시점부터 1초 간격으로 실행 되기 때문에 2초가 지난 후 바로 실행된다.
// OutPut
FixedDelayJob = 2021-12-07 14:05:42.568
scheduling-1
FixedDelayJob = 2021-12-07 14:05:44.573
scheduling-1
FixedDelayJob = 2021-12-07 14:05:46.575
scheduling-1
실제로 1초 간격으로 실행되기 위해서는 비동기화가 필요하다.
비동기화
이제 fixedRate 코드 메서드에 @Async 를 붙여주면 비동기 작업을 지원해 일정 간격으로 실행된다.
하지만 작업이 길어 쓰레드가 모두 사용중이라면 대기 시간을 가지게 된다.
@Component
@EnableScheduling
@EnableAsync
public class Scheduler {
@Scheduled(fixedRate = 100) // 1초 간격 실행
@Async
public void fixedRateJob() throws InterruptedException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
Date now = new Date();
String strDate = sdf.format(now);
System.out.println("FixedDelayJob = " + strDate);
System.out.println(Thread.currentThread().getName());
Thread.sleep(3000);
}
}
@Async 사용을 위해 @EnableAsync 어노테이션으로 스프링에게 비동기 사용을 알린다.
// OutPut
FixedDelayJob = 2021-12-07 15:42:00.487
task-1
FixedDelayJob = 2021-12-07 15:42:01.481
task-2
FixedDelayJob = 2021-12-07 15:42:02.478
task-3
FixedDelayJob = 2021-12-07 15:42:03.478
task-4
FixedDelayJob = 2021-12-07 15:42:04.478
task-5
여러 스케줄 동시 작업
기본적으로 스케쥴이 사용하는 스레드는 하나이므로 수행해야 할 작업이 여러개라면 스레드 락이 걸릴 수 있다.
따라서 아래와 같이 스레드풀을 사용하도록 설정한다.
@Configuration
public class SchdulerConfig implements SchedulingConfigurer {
private final int POOL_SIZE = 10;
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(POOL_SIZE); // 대기하는 스레드 개수
threadPoolTaskScheduler.setThreadNamePrefix("my-scheduled-task-pool-"); // 스레드 이름
threadPoolTaskScheduler.initialize();
scheduledTaskRegistrar.setTaskScheduler(threadPoolTaskScheduler);
}
}
아래와 같이 사용한다.
@Component
@EnableScheduling
public class Scheduler {
@Scheduled(fixedDelay = 1000) // 작업 후 1초 후 실행
public void fixedDelayJob() throws InterruptedException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
Date now = new Date();
String strDate = sdf.format(now);
System.out.println("FixedDelayJob = " + strDate);
System.out.println(Thread.currentThread().getName());
}
@Scheduled(fixedRate = 1000) // 1초 간격
public void fixedRateJob() throws InterruptedException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
Date now = new Date();
String strDate = sdf.format(now);
System.out.println("FixedDelayJob = " + strDate);
System.out.println(Thread.currentThread().getName());
}
}
// OutPut
FixedDelayJob = 2021-12-07 15:56:42.973
jin-Scheduling2
FixedDelayJob = 2021-12-07 15:56:42.973
jin-Scheduling1
FixedDelayJob = 2021-12-07 15:56:43.973
jin-Scheduling3
FixedDelayJob = 2021-12-07 15:56:43.974
jin-Scheduling4
FixedDelayJob = 2021-12-07 15:56:44.973
jin-Scheduling2
FixedDelayJob = 2021-12-07 15:56:44.974
jin-Scheduling5
FixedDelayJob = 2021-12-07 15:56:45.975
jin-Scheduling6