자바 스케줄링

Rashmi Patidar 2023년10월12일
  1. Java의 ScheduledExecutorService 인터페이스 메서드를 사용하여 프로세스 예약
  2. Java의 Timer 클래스를 사용하여 스레드 예약
자바 스케줄링

스케줄링은 정해진 시간 간격으로 작업이나 기능을 실행하는 프로세스입니다. 스케줄링은 배치 프로세스 실행, 생일 축하와 같은 이벤트 기반 트리거 전송, 푸시 알림 전송에서 사용법을 찾습니다. 이러한 프로세스는 주어진 조건과 시간 간격에 따라 잘 정의된 시간에 실행되어야 합니다.

Java의 ScheduledExecutorService 인터페이스 메서드를 사용하여 프로세스 예약

package scheduling;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

public class ScheduleTask {
  private static int counter = 0;

  public static void main(String[] args) throws InterruptedException {
    ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
    Runnable executeTask = () -> {
      counter++;
      System.out.println("Task" + counter);
    };

    ScheduledFuture<?> scheduleAtFixedRate =
        service.scheduleAtFixedRate(executeTask, 5, 1, TimeUnit.SECONDS);

    while (true) {
      Thread.sleep(1000);
      if (counter == 5) {
        System.out.println("Stopping the scheduled task!");
        scheduleAtFixedRate.cancel(true);
        service.shutdown();
        break;
      }
    }
  }
}

위의 코드에서는 먼저 정적 카운터 변수를 0 값으로 초기화합니다. newScheduledThreadPoolExecutors 클래스의 정적 메서드입니다. 이 메서드는 인수 목록에 지정된 매개 변수를 사용하여 주기적으로 실행해야 하는 스레드 풀을 만듭니다. 따라서 우리의 경우 메소드의 인수 목록에 있는 매개변수가 스레드 풀의 수를 정의하므로 실행을 위해 단일 스레드가 생성됩니다. 메서드는 service 참조 변수에 저장되는 ScheduledExecutorService 인스턴스를 반환하고 풀 크기가 0보다 작으면 IllegalArgumentException을 throw합니다.

Runnable은 모든 클래스가 확장할 수 있는 인터페이스이며 기능적 인터페이스입니다. run 메서드로 하나의 정적 메서드만 있으며 스레드가 실행할 수 있습니다. ()-> 기호와 화살표로 표현된 람다 식을 사용하여 구조는 실행 메서드에 인수를 전달하지 않는다는 것을 나타냅니다. run 메소드의 정의에서 명령문을 정의했습니다. 블록 내부에 있는 명령문은 카운터 변수를 증가시키고 콘솔 출력에 작업을 인쇄합니다. 이러한 모든 명령문은 executeTask 변수라는 변수에 의해 참조됩니다.

service 참조 변수는 ScheduledExecutorService 인터페이스의 scheduleAtFixedRate 메소드를 호출합니다. 이 메서드는 초기 지연 이후에 지정된 기간 내에 나중에 실행되어야 하는 주기적 작업을 생성하고 실행합니다. 실행해야 하는 runnable 명령의 4가지 매개변수가 필요하며 initialDelay 변수는 첫 번째 실행을 지연하는 시간, period는 연속 실행 사이의 기간, unit은 초 단위 시간 단위입니다, 분 및 시간. 스레드는 메서드가 호출되는 즉시 실행을 시작합니다.

while 루프에서 먼저 현재 실행 중인 스레드가 강제로 절전 모드로 전환됩니다. Thread.sleep() 메서드는 현재 실행 중인 스레드를 정의된 시간 동안 일시적으로 중지합니다. 매개변수는 현재 작업 스레드가 정지해야 하는 시간(밀리초)입니다. 이 메서드는 값이 음수이면 IllegalArgumentException을 throw하고 현재 스레드가 중단되면 InterruptedException을 throw합니다. 나중에 카운터 값은 정의된 값으로 확인됩니다. 이 검사는 일정 횟수 동안 while 메서드를 실행하는 데 적용됩니다. 그렇지 않으면 블록은 절대 종료되지 않는 무한 수에 대해 작동합니다. while 블록에서 scheduleAtFixedRate 변수는 cancel 메서드를 호출하여 스레드의 현재 실행을 취소합니다. 이 함수는 또한 현재 실행 중인 스레드가 인터럽트할 수 있는지 여부를 나타내는 부울 매개변수를 사용합니다.

service.shutdown 메소드는 이전에 제출된 작업이 실행되어야 하는 종료 프로세스를 시작하고 새로운 것은 허용되지 않습니다.

위 코드 블록의 출력은 아래와 같습니다.

Task1
Task2
Task3
Task4
Task5
Stopping the scheduled task!

Java의 Timer 클래스를 사용하여 스레드 예약

다음은 생성자를 사용하여 두 개의 사용자 정의 클래스 개체를 인스턴스화하는 간단한 코드 블록입니다. TimerImplementation은 동일한 사용자 정의 클래스입니다. 새 스레드를 생성할 Timer 인스턴스가 생성됩니다. 새로 생성된 타이머 개체는 scheduleAtFixedRate 메서드를 호출합니다. 이 메서드는 매개변수를 예약해야 하는 task로 사용하고 delay는 작업을 밀리초 단위로 지연하며 period는 연속 실행 시간을 밀리초 단위로 나타냅니다.

package timer;

import java.util.Timer;

public class UsingTimerClass {
  public static void main(String[] args) {
    TimerImplementation timer1 = new TimerImplementation("Thread1");
    TimerImplementation timer2 = new TimerImplementation("Thread2");

    Timer t = new Timer();
    t.scheduleAtFixedRate(timer1, 0, 2000);
    t.scheduleAtFixedRate(timer2, 0, 1000);
  }
}

다음은 사용자 정의 클래스의 구현입니다. TimerImplementation 클래스는 run이라는 단일 추상 메소드를 보유하는 TimerTask 추상 클래스를 확장합니다. 사용자 정의 클래스에서 TimerTask 클래스를 확장하면 run 메서드가 재정의됩니다.

클래스에는 사용자 정의 이름을 스레드 개체로 설정하는 하나의 사용자 정의 생성자가 있습니다.

스레드 run 메소드에서 실제 논리를 제공할 수 있습니다. 여기에는 현재 실행 중인 스레드의 이름을 인쇄하는 print라는 문이 포함됩니다. Thread.currentThread().getName()은 현재 실행 중인 스레드의 이름을 반환합니다. sleep 메서드는 1000밀리초 동안 실행을 중단하는 Thread1을 통해 호출됩니다. sleep 메소드는 스레드가 현재 스레드를 인터럽트하면 InterruptedException을 던지고 이것이 try-catch 블록으로 묶이는 이유입니다.

package timer;

import java.util.TimerTask;

public class TimerImplementation extends TimerTask {
  private String name;

  public TimerImplementation(String n) {
    this.name = n;
  }

  @Override
  public void run() {
    System.out.println(Thread.currentThread().getName() + " " + name);
    if ("Thread1".equalsIgnoreCase(name)) {
      try {
        Thread.sleep(1000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }
}

아래는 위 코드의 끝없는 출력입니다. run 메소드에서 종료 조건을 정의하지 않았기 때문에 스레드는 메인 스레드 실행을 종료하기 위해 외부 정지가 적용될 때까지 끝없이 실행됩니다.

Timer-0 Thread1
Timer-0 Thread2
Timer-0 Thread2
Timer-0 Thread2
Timer-0 Thread1
Timer-0 Thread2
Timer-0 Thread2
Timer-0 Thread1
Timer-0 Thread2
Rashmi Patidar avatar Rashmi Patidar avatar

Rashmi is a professional Software Developer with hands on over varied tech stack. She has been working on Java, Springboot, Microservices, Typescript, MySQL, Graphql and more. She loves to spread knowledge via her writings. She is keen taking up new things and adopt in her career.

LinkedIn