자바 - 스레드 스케줄러

안녕하세요, 미래의 자바 마법사 여러분! 오늘은 자바 스레드 스케줄링의 흥미로운 세계로 여행을 떠날 거예요. 프로그래밍에 새로운 사람이라도 걱정하지 마세요 – 저는 여러분의 친절한 가이드가 될 테니까요. 이 주제를 단계별로 해결해 나가겠습니다. 그럼, 가상의 지팡이(키보드)를 잡고, 함께 빠져나가요!

Java - Thread Scheduler

스레드 스케줄링이란?

자세히 들어가기 전에, 스레드 스케줄링이란 무엇인지 이해해 봅시다. 여러분이马戏团의 매니저(자바 런타임)라고 상상해봅시다. 여러 연주자(스레드)가 자신의 공연을 기다리고 있는데, 누가 무대에 올지와 얼마 동안 할지를 결정하는 것이 여러분의 일이라고 생각해봅시다. 이것이 바로 자바에서 스레드 스케줄링이 하는 일입니다 – 여러 스레드를 관리하고, 어느 스레드가 언제 실행될지를 결정합니다.

왜 스레드 스케줄링이 필요한가요?

"모든 스레드가 원하는대로 실행되면 안 되나요?"라고 궁금해할 수도 있습니다. 하지만 만약 모든 연주자가 한 번에 공연을 시도한다면,混沌이 벌어질 텐데요! 스레드 스케줄링은 순서를 유지하고, 公平한 자원 할당을 보장하며, 전체 시스템 성능을 향상시키는 데 도움이 됩니다.

자바의 스레드 스케줄러

자바는 우리를 위해 이 복잡한 작업을 처리하는 내장형 스레드 스케줄러를 가지고 있습니다. 이 스케줄러는 운영 체제 수준의 스케줄링과 자신의 알고리즘을 조합하여 스레드를 효율적으로 관리합니다.

스레드 상태

스케줄링에 들어가기 전에, 스레드가 가질 수 있는 다양한 상태를 빠르게 살펴보겠습니다:

  1. New
  2. Runnable
  3. Running
  4. Blocked/Waiting
  5. Terminated

스케줄러는 이러한 상태들 간에 스레드를 이동시켜야 합니다.

기본적인 스레드 생성과 스케줄링

자바가 어떻게 스레드를 생성하고 스케줄링하는지를 간단한 예제를 통해 볼게요:

public class SimpleThreadExample {
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("Thread 1: " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});

Thread thread2 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("Thread 2: " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});

thread1.start();
thread2.start();
}
}

이 예제에서는 숫자 0부터 4까지 인쇄하는 두 개의 스레드를 생성합니다. Thread.sleep(1000) 호출은 각 스레드가 인쇄 사이에 1초 동안 일시 중지합니다.

이 프로그램을 실행하면, 출력이 완벽한 번갈아가며 순서로 나타나지 않을 수 있습니다. 이는 자바 스케줄러가 언제 스레드를 전환할지를 결정하고 있기 때문입니다!

스레드 우선순위

자바는 스케줄러에게 어느 스레드가 더 중요한지에 대한 힌트를 주는 것을 허용합니다. 우리는 setPriority() 메서드를 사용하여 스레드 우선순위를 설정할 수 있습니다. 이전 예제를 수정해 봅시다:

public class ThreadPriorityExample {
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("Low Priority Thread: " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});

Thread thread2 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("High Priority Thread: " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});

thread1.setPriority(Thread.MIN_PRIORITY);
thread2.setPriority(Thread.MAX_PRIORITY);

thread1.start();
thread2.start();
}
}

이 예제에서는 thread1을 가장 낮은 우선순위로 설정하고, thread2를 가장 높은 우선순위로 설정합니다. 이것은 thread2가 항상 먼저 실행되거나 더 많이 실행될 것을 보장하지는 않지만, 스케줄러에게 thread2를 가능한 한 선호하도록 힌트를 줍니다.

ScheduledExecutorService

이제 더 고급적인 방법으로 ScheduledExecutorService를 사용하여 스레드를 스케줄링하는 방법을 살펴보겠습니다. 이 강력한 도구는 우리가 작업을 지연 후에나 고정된 간격으로 실행하도록 예약할 수 있게 합니다.

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

public class ScheduledExecutorExample {
public static void main(String[] args) {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);

Runnable task1 = () -> System.out.println("Task 1 executed at: " + System.currentTimeMillis());
Runnable task2 = () -> System.out.println("Task 2 executed at: " + System.currentTimeMillis());

executor.schedule(task1, 5, TimeUnit.SECONDS);
executor.scheduleAtFixedRate(task2, 0, 2, TimeUnit.SECONDS);

try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}

executor.shutdown();
}
}

이 예제에서:

  • 우리는 2개의 스레드를 가진 ScheduledExecutorService를 생성합니다.
  • task1은 5초 지연 후에 한 번 실행됩니다.
  • task2는 즉시 시작하여 2초 간격으로 반복됩니다.
  • 프로그램이 10초 동안 실행된 후에 실행기를 종료합니다.

이렇게 우리는 작업이 언제와 얼마나 자주 실행될지 정확히 제어할 수 있습니다.

ScheduledExecutorService 메서드

여기는 ScheduledExecutorService가 제공하는 주요 메서드들의 표입니다:

메서드 설명
schedule(Runnable, long, TimeUnit) 지정된 지연 후에 한 번 실행되는 작업을 예약합니다
scheduleAtFixedRate(Runnable, long, long, TimeUnit) 고정된 간격으로 실행되는 작업을 예약합니다, 각 실행의 시작 간격이 고정됩니다
scheduleWithFixedDelay(Runnable, long, long, TimeUnit) 고정된 간격으로 실행되는 작업을 예약합니다, 한 실행의 끝과 다음 실행의 시작 간격이 고정됩니다

결론

그렇게 끝내죠, 여러분! 우리는 자바 스레드 스케줄링의 기본 개념부터 ScheduledExecutorService를 사용한 고급 스케줄링까지 여행을 했습니다. 스레드 스케줄링은 오케스트라를 이끌어가는 것과 마찬가지입니다 – 모든 것은 조화와 시간에 관련이 있습니다.

자바의 모험을 계속하면서, 스레드 행동을 더욱 세부적으로 조정할 수 있는 방법을 더 많이 발견할 거예요. 하지만 지금은 자신에게 박수를 쳐봅시다 – 동시 프로그래밍의 세계로 큰 발걸음을 내딛었답니다!

연습을 계속하고, 호기심을 유지하며, 가장 중요한 것은 코딩하는 것을 즐기세요! 아마도 어느 날이 되면, 여러분이 다음 세대의 자바 스레드 스케줄러를 작성하는 사람이 될지도 모릅니다. 그 때까지, 즐거운 스레딩 되세요!

Credits: Image by storyset