# 자바 - 스레드 제어

안녕하세요, 미래의 자바 마법사 여러분! 오늘 우리는 자바 스레드 제어의 fascinatig한 세상으로 빠져들어갈 거예요. 프로그래밍에 새로운 사람이라면 걱정하지 마세요 - 저는 여러분을 단계별로 안내해드릴 것입니다. 수 년간 수많은 학생들에게 했던 것처럼 말이죠. 그럼 가상의魔杖( 키보드)을 잡고, 코드 마법을 만들어보세요!

Java - Thread Control

스레드는 무엇인가요?

스레드 제어에 뛰어들기 전에 스레드가 무엇인지 이해해보겠습니다. 생각해보세요, 복잡한 식사를 요리하는 주방에서 당신이 있을 때. 당신은 주요 프로그램이고, 당신이 하는 각 작업( 채소 썰기, 소스 저어주기, 오븐 확인하기)은 스레드와 같습니다. 이들은 모두 동일한 전체 과정( 저녁 식사 만들기)의 일부이지만, 동시에 일어날 수 있는 별도의 작업입니다.

자바에서 스레드는 가벼운 서브프로세스로, 처리의 가장 작은 단위입니다. 프로그램 내에서 특정 작업을 위한 별도의 실행 경로를 만드는 방법입니다.

스레드 제어의 이유는 무엇인가요?

그럼 왜 이 스레드를 제어하고 싶을까요? 우리는 계속 요리에 대한 비유를 사용하겠습니다. 가끔씩, 소스를 저어주는 것을 잠시 멈추고 로스트를 확인해야 할 수도 있습니다. 또는 파스타를 넣기 전에 물이 끓기를 기다려야 할 수도 있습니다. 마찬가지로, 프로그래밍에서도 우리는 자주 다른 스레드의 흐름과 시간을 제어하여 프로그램이 부드럽고 효율적으로 실행되도록 해야 합니다.

자바 스레드 제어 방법

자바는 스레드를 제어하는 여러 가지 방법을 제공합니다. 이들을 편리한 표로 보겠습니다:

메서드 설명
start() 스레드를 시작하고, run() 메서드가 호출되도록 합니다
run() 스레드의 작업을 구성하는 코드를 포함합니다
sleep() 스레드가 지정된 시간 동안 일시 중지합니다
join() 스레드가 종료할 때까지 기다립니다
yield() 스레드가 잠시 중지하고 다른 스레드가 실행되도록 합니다
interrupt() 스레드를 중断합니다
isAlive() 스레드가 여전히 실행 중인지 확인합니다

이제 이 메서드들을 몇 가지 예제와 함께 살펴보겠습니다!

1. start()과 run()

이 두 메서드는 함께 작동합니다. 간단한 예제를 보겠습니다:

public class MyThread extends Thread {
    public void run() {
        System.out.println("My thread is running!");
    }

    public static void main(String args[]) {
        MyThread thread = new MyThread();
        thread.start();
    }
}

이 예제에서 우리는 새로운 스레드를 생성하고 그 start() 메서드를 호출합니다. 이는 run() 메서드를 호출하여 스레드가 실행할 실제 코드를 실행합니다.

2. sleep()

sleep() 메서드는 알람 시계의 슬리프 버튼을 누르는 것과 같습니다. 스레드가 지정된 시간 동안 실행을 중지합니다. 다음과 같이 작동합니다:

public class SleepyThread extends Thread {
    public void run() {
        for (int i = 1; i <= 5; i++) {
            System.out.println("Thread is counting: " + i);
            try {
                Thread.sleep(1000); // 1초 동안 중지
            } catch (InterruptedException e) {
                System.out.println("Thread was interrupted!");
            }
        }
    }

    public static void main(String args[]) {
        SleepyThread thread = new SleepyThread();
        thread.start();
    }
}

이 스레드는 1에서 5까지 카운팅하며, 각 카운트 사이에 1초를 중지합니다. 마치 천천히 양을 세는 졸린 사람처럼!

3. join()

join() 메서드는 친구가 작업을 마치기 전에 점심을 먹기 위해 기다리는 것과 같습니다. 현재 스레드가 다른 스레드가 실행을 마치기를 기다립니다. 다음 예제를 보겠습니다:

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

        Thread t2 = new Thread(() -> {
            try {
                t1.join(); // t1이 마치기를 기다림
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Thread 2: I'm done waiting!");
        });

        t1.start();
        t2.start();
    }
}

이 예제에서 Thread 2는 Thread 1이 마치기를 기다렸다가 메시지를 출력합니다.

4. yield()

yield() 메서드는 대화에서 예의를 표하는 것과 같습니다. 스레드가 잠시 중지하고 같은 우선순위의 다른 스레드가 실행되도록 합니다. 그러나 이는 스케줄러에 대한 단순한 제안일 뿐, 무시될 수 있습니다. 간단한 예제를 보겠습니다:

public class YieldExample implements Runnable {
    public void run() {
        for (int i = 0; i < 3; i++) {
            System.out.println(Thread.currentThread().getName() + " in control");
            Thread.yield();
        }
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(new YieldExample(), "Thread 1");
        Thread t2 = new Thread(new YieldExample(), "Thread 2");
        t1.start();
        t2.start();
    }
}

스레드가 번갈아가며 제어를 맡을 수 있지만, 이는 보장되지 않습니다!

5. interrupt()

interrupt() 메서드는 누군가의 어깨를 툭치는 것과 같습니다. 스레드를 즉시 중단하지는 않지만, 스레드가 확인할 수 있는 깃발을 설정합니다. 다음과 같이 작동합니다:

public class InterruptExample implements Runnable {
    public void run() {
        try {
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("Thread is running...");
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            System.out.println("Thread was interrupted while sleeping");
        }
        System.out.println("Thread has finished.");
    }

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new InterruptExample());
        thread.start();
        Thread.sleep(5000); // 5초 동안 스레드가 실행되도록 합니다
        thread.interrupt();
    }
}

이 예제에서 스레드는 5초 후에 중断됩니다.

6. isAlive()

isAlive() 메서드는 누군가가 데스크에 있는지 확인하는 것과 같습니다. 스레드가 여전히 실행 중인지 확인합니다. 빠른 예제를 보겠습니다:

public class AliveExample extends Thread {
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("Thread is running: " + i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        AliveExample thread = new AliveExample();
        thread.start();

        while (thread.isAlive()) {
            System.out.println("Main thread will wait until MyThread is alive");
            Thread.sleep(1500);
        }
        System.out.println("Main thread is run to completion");
    }
}

이 예제에서 주요 스레드는 커스텀 스레드가 여전히 실행 중인지 기다립니다.

마무리

이제 여러분은 자바 스레드 제어의 땅을 여행하고, 각 메서드를 모험가처럼 탐험했습니다. 기억하시기 바랍니다, 요리를 배우는 것처럼, 스레드 제어를 마스터하려면 연습이 필요합니다. 두려워 말고 이 메서드들을 자신의 코드에서 실험해보세요.

이 수업을 마치면서, 한 학생이 스레드를 다양한 주방에서 함께 일하는 요리사로 상상하면 이해가 "들어오는" 것을 말한 적이 떠오릅니다. 자신에게 맞는 비유를 찾아보세요!

계속 코딩하고, 배우고, 가장 중요한 것은 즐겁게 하세요! 누구 knows? 다음 큰 다중 스레드 애플리케이션이 여러분 중 한 명에서 나올 수도 있습니다. 다음 시간까지, 스레드가 부드럽게 실행되고, 코드가 버그가 없기를 바랍니다!

Credits: Image by storyset