λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
μΉ΄ν…Œκ³ λ¦¬ μ—†μŒ

μžλ°” Thread(μŠ€λ ˆλ“œ) μ‚¬μš©λ²• & 예제

by 5566 2023. 10. 29.

λͺ©μ°¨:

1. μŠ€λ ˆλ“œ(Thread)λž€ 무엇인가?

2. μžλ°”μ—μ„œμ˜ μŠ€λ ˆλ“œ μ‚¬μš©λ²•

3. μŠ€λ ˆλ“œ μ‘°μž‘(Manipulating Threads)

4. 닀쀑 μŠ€λ ˆλ“œ ν™˜κ²½μ—μ„œμ˜ 동기화(Synchronization)

5. μžλ°” μŠ€λ ˆλ“œ 예제

1. μŠ€λ ˆλ“œ(Thread)λž€ 무엇인가?

μŠ€λ ˆλ“œ(Thread)λŠ” ν”„λ‘œκ·Έλž¨ λ‚΄μ—μ„œ λ™μ‹œμ— μ‹€ν–‰λ˜λŠ” 일련의 μž‘μ—… λ‹¨μœ„λ₯Ό λ§ν•©λ‹ˆλ‹€. μŠ€λ ˆλ“œλŠ” ν”„λ‘œμ„ΈμŠ€ λ‚΄μ—μ„œ λ…λ¦½μ μœΌλ‘œ μ‹€ν–‰λ˜λ©°, λ™μ‹œμ— μ—¬λŸ¬ μž‘μ—…μ„ μˆ˜ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

일반적으둜 ν”„λ‘œκ·Έλž¨μ„ μ‹€ν–‰ν•  λ•Œ, ν”„λ‘œμ„ΈμŠ€λŠ” 단일 μŠ€λ ˆλ“œλ‘œ μ‹€ν–‰λ˜λ©° μž‘μ—…μ€ 순차적으둜 μˆ˜ν–‰λ©λ‹ˆλ‹€. ν•˜μ§€λ§Œ μŠ€λ ˆλ“œλ₯Ό μ‚¬μš©ν•˜λ©΄ μ—¬λŸ¬ μž‘μ—…μ„ λ™μ‹œμ— μ‹€ν–‰ν•  수 μžˆμœΌλ―€λ‘œ, 닀쀑 μŠ€λ ˆλ“œ ν™˜κ²½μ—μ„œ ν”„λ‘œμ„ΈμŠ€μ˜ μ‹€ν–‰ μ‹œκ°„μ„ 쀄이고 μ„±λŠ₯을 ν–₯μƒμ‹œν‚¬ 수 μžˆμŠ΅λ‹ˆλ‹€.

μŠ€λ ˆλ“œλŠ” μžμ‹ μ˜ μ‹€ν–‰ μ»¨ν…μŠ€νŠΈ, μŠ€νƒ, λ ˆμ§€μŠ€ν„° 등을 가지며, 독립적인 μ‹€ν–‰ 흐름을 κ°–κ³  μžˆμŠ΅λ‹ˆλ‹€. λ™μΌν•œ ν”„λ‘œμ„ΈμŠ€ λ‚΄μ—μ„œ μ—¬λŸ¬ μŠ€λ ˆλ“œκ°€ λ™μ‹œμ— 싀행될 수 있고, 각 μŠ€λ ˆλ“œλŠ” μ„œλ‘œ κ³΅μœ λ˜λŠ” λ©”λͺ¨λ¦¬ 곡간에 μ ‘κ·Όν•˜μ—¬ 데이터λ₯Ό κ³΅μœ ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μŠ€λ ˆλ“œλŠ” 주둜 병렬성을 ν™œμš©ν•˜μ—¬ λ™μ‹œμ— μ—¬λŸ¬ μž‘μ—…μ„ μ²˜λ¦¬ν•˜κΈ° μœ„ν•΄ μ‚¬μš©λ©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, μ›Ή μ„œλ²„μ—μ„œ ν΄λΌμ΄μ–ΈνŠΈ μš”μ²­μ„ λ™μ‹œμ— μ²˜λ¦¬ν•˜λŠ” 경우, 각 ν΄λΌμ΄μ–ΈνŠΈ μš”μ²­μ„ μŠ€λ ˆλ“œλ‘œ μ²˜λ¦¬ν•˜μ—¬ λ³‘λ ¬μ μœΌλ‘œ μ‹€ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μŠ€λ ˆλ“œλŠ” λ‹€μŒκ³Ό 같은 μž₯점을 가지고 μžˆμŠ΅λ‹ˆλ‹€:

  • λΉ λ₯Έ 응닡 μ‹œκ°„: μ—¬λŸ¬ μž‘μ—…μ„ λ™μ‹œμ— μ²˜λ¦¬ν•¨μœΌλ‘œμ¨ 응닡 μ‹œκ°„μ„ λ‹¨μΆ•μ‹œν‚¬ 수 μžˆμŠ΅λ‹ˆλ‹€.
  • μžμ› 곡유: μ—¬λŸ¬ μŠ€λ ˆλ“œλŠ” ν”„λ‘œμ„ΈμŠ€ λ‚΄μ—μ„œ λ©”λͺ¨λ¦¬ 곡간을 κ³΅μœ ν•  수 μžˆμœΌλ―€λ‘œ, 데이터 κ³΅μœ μ™€ 효율적인 μžμ› μ‚¬μš©μ΄ κ°€λŠ₯ν•©λ‹ˆλ‹€.
  • κ²½μ œμ„±: μŠ€λ ˆλ“œλŠ” ν”„λ‘œμ„ΈμŠ€λ₯Ό μƒμ„±ν•˜λŠ” 것보닀 경제적으둜 생성 및 κ΄€λ¦¬ν•˜κΈ° λ•Œλ¬Έμ— μ‹œμŠ€ν…œ μžμ›μ„ 효율적으둜 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

ν•˜μ§€λ§Œ μŠ€λ ˆλ“œλ₯Ό μ‚¬μš©ν•  λ•Œ μ£Όμ˜ν•΄μ•Ό ν•  λͺ‡ 가지 단점도 μžˆμŠ΅λ‹ˆλ‹€:

  • λ³΅μž‘μ„±: μŠ€λ ˆλ“œλ₯Ό μ‚¬μš©ν•˜λ©΄ λ™μ‹œμ„± λ¬Έμ œμ™€ 동기화 문제 λ“± λ³΅μž‘ν•œ 상황에 직면할 수 μžˆμŠ΅λ‹ˆλ‹€.
  • μƒν˜Έμž‘μš© 문제: μ—¬λŸ¬ μŠ€λ ˆλ“œκ°€ λ™μ‹œμ— λ©”λͺ¨λ¦¬λ₯Ό μˆ˜μ •ν•˜λŠ” 경우, 데이터 일관성을 μœ μ§€ν•˜κΈ° μœ„ν•œ μ‘°μΉ˜κ°€ ν•„μš”ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • λ°λ“œλ½: μ—¬λŸ¬ μŠ€λ ˆλ“œκ°€ μƒν˜Έκ°„μ— μ„œλ‘œμ˜ μž‘μ—…μ„ κΈ°λ‹€λ¦¬λŠ” 상황이 λ°œμƒν•˜μ—¬ λ¬΄ν•œ λŒ€κΈ° μƒνƒœμ— 빠질 수 μžˆλŠ” λ°λ“œλ½(deadlock) λ¬Έμ œκ°€ μžˆμ„ 수 μžˆμŠ΅λ‹ˆλ‹€.

μŠ€λ ˆλ“œλ₯Ό 효과적으둜 ν™œμš©ν•˜κΈ° μœ„ν•΄μ„œλŠ” 동기화 λ¬Έμ œμ™€ μƒν˜Έμž‘μš© 문제λ₯Ό κ³ λ €ν•˜κ³  μ μ ˆν•œ μžμ› 곡유 기법을 μ‚¬μš©ν•˜μ—¬ 닀쀑 μŠ€λ ˆλ“œ ν™˜κ²½μ„ 관리해야 ν•©λ‹ˆλ‹€.

2. μžλ°”μ—μ„œμ˜ μŠ€λ ˆλ“œ μ‚¬μš©λ²•

μžλ°”μ—μ„œ μŠ€λ ˆλ“œλ₯Ό μ‚¬μš©ν•˜κΈ° μœ„ν•΄ java.lang.Thread 클래슀λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€. Thread ν΄λž˜μŠ€λŠ” μŠ€λ ˆλ“œμ˜ 생성 및 μ œμ–΄μ— μ‚¬μš©λ˜λ©°, λ‹€μŒκ³Ό 같은 λ°©λ²•μœΌλ‘œ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μŠ€λ ˆλ“œ 생성

μŠ€λ ˆλ“œλ₯Ό μƒμ„±ν•˜κΈ° μœ„ν•΄μ„œλŠ” Thread 클래슀λ₯Ό μƒμ†λ°›μ•„μ„œ μƒˆλ‘œμš΄ 클래슀λ₯Ό μ •μ˜ν•˜κ±°λ‚˜, Runnable μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜λŠ” 방법을 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

1. Thread 클래슀λ₯Ό 상속받은 방법:

public class MyThread extends Thread {
    public void run() {
        // μŠ€λ ˆλ“œμ—μ„œ μ‹€ν–‰ν•  μž‘μ—…μ„ κ΅¬ν˜„
    }
}

μœ„μ™€ 같이 Thread 클래슀λ₯Ό 상속받은 μžμ‹ ν΄λž˜μŠ€μ—μ„œ run λ©”μ„œλ“œλ₯Ό μ˜€λ²„λΌμ΄λ”©ν•˜μ—¬ μŠ€λ ˆλ“œμ—μ„œ μ‹€ν–‰ν•  μž‘μ—…μ„ κ΅¬ν˜„ν•©λ‹ˆλ‹€.

2. Runnable μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜λŠ” 방법:

public class MyRunnable implements Runnable {
    public void run() {
        // μŠ€λ ˆλ“œμ—μ„œ μ‹€ν–‰ν•  μž‘μ—…μ„ κ΅¬ν˜„
    }
}

μœ„μ™€ 같이 Runnable μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜λŠ” ν΄λž˜μŠ€μ—μ„œ run λ©”μ„œλ“œλ₯Ό κ΅¬ν˜„ν•©λ‹ˆλ‹€.

μŠ€λ ˆλ“œ μ‹œμž‘

μŠ€λ ˆλ“œλ₯Ό μ‹œμž‘ν•˜κΈ° μœ„ν•΄μ„œλŠ” start λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•΄μ•Ό ν•©λ‹ˆλ‹€. start λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄, μŠ€λ ˆλ“œκ°€ λ…λ¦½μ μœΌλ‘œ μ‹€ν–‰λ˜λ©° run λ©”μ„œλ“œμ˜ μ½”λ“œκ°€ μ‹€ν–‰λ©λ‹ˆλ‹€.

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

μœ„μ˜ μ˜ˆμ œμ—μ„œ MyThread ν΄λž˜μŠ€λŠ” Thread 클래슀λ₯Ό 상속받은 μžμ‹ ν΄λž˜μŠ€μž…λ‹ˆλ‹€. start λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜μ—¬ μŠ€λ ˆλ“œλ₯Ό μ‹œμž‘ν•©λ‹ˆλ‹€.

μŠ€λ ˆλ“œ μ œμ–΄

μŠ€λ ˆλ“œλ₯Ό μ œμ–΄ν•˜κΈ° μœ„ν•΄ λ‹€μŒκ³Ό 같은 λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

  • join(): ν•΄λ‹Ή μŠ€λ ˆλ“œκ°€ μ’…λ£Œλ  λ•ŒκΉŒμ§€ ν˜ΈμΆœν•œ μŠ€λ ˆλ“œλ₯Ό λΈ”λ‘ν•©λ‹ˆλ‹€.
  • yield(): ν˜„μž¬ μ‹€ν–‰ 쀑인 μŠ€λ ˆλ“œλ₯Ό μΌμ‹œμ μœΌλ‘œ λ©ˆμΆ”κ³  λ‹€λ₯Έ μŠ€λ ˆλ“œμ—κ²Œ μ‹€ν–‰ 기회λ₯Ό μ–‘λ³΄ν•©λ‹ˆλ‹€.
  • sleep(long millis): ν˜„μž¬ μ‹€ν–‰ 쀑인 μŠ€λ ˆλ“œλ₯Ό μ§€μ •λœ μ‹œκ°„ λ™μ•ˆ 멈μΆ₯λ‹ˆλ‹€.
  • interrupt(): μŠ€λ ˆλ“œκ°€ λΈ”λ‘λ˜μ–΄ μžˆλŠ” μƒνƒœμ—μ„œ μΌμ‹œμ μœΌλ‘œ λ©ˆμΆ”κ²Œ ν•˜κ±°λ‚˜, μŠ€λ ˆλ“œλ₯Ό μ’…λ£Œμ‹œν‚€κΈ° μœ„ν•΄ μ‚¬μš©λ©λ‹ˆλ‹€.
public static void main(String[] args) {
    MyThread thread1 = new MyThread();
    MyThread thread2 = new MyThread();

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

    try {
        thread1.join();
        thread2.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

μœ„μ˜ μ˜ˆμ œμ—μ„œ join λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ thread1κ³Ό thread2κ°€ μ’…λ£Œλ  λ•ŒκΉŒμ§€ main μŠ€λ ˆλ“œλ₯Ό λΈ”λ‘ν•©λ‹ˆλ‹€. 이둜써 thread1κ³Ό thread2κ°€ 싀행을 마치고 μ’…λ£Œλœ 후에 main μŠ€λ ˆλ“œκ°€ 계속 μ§„ν–‰λ©λ‹ˆλ‹€.

μŠ€λ ˆλ“œ μš°μ„ μˆœμœ„

μŠ€λ ˆλ“œμ˜ μš°μ„ μˆœμœ„λŠ” μ‹€ν–‰ν•  λ•Œ CPU μžμ›μ„ 얻을 ν™•λ₯ μ„ κ²°μ •ν•˜λŠ”λ° μ‚¬μš©λ©λ‹ˆλ‹€. μžλ°”μ—μ„œλŠ” μŠ€λ ˆλ“œμ˜ μš°μ„ μˆœμœ„λ₯Ό 1μ—μ„œ 10μ‚¬μ΄μ˜ κ°’μœΌλ‘œ μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 기본적으둜 λͺ¨λ“  μŠ€λ ˆλ“œμ˜ μš°μ„ μˆœμœ„λŠ” 5둜 μ„€μ •λ©λ‹ˆλ‹€.

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

    public static void main(String[] args) {
        MyThread thread1 = new MyThread();
        MyThread thread2 = new MyThread();

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

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

μœ„μ˜ μ˜ˆμ œμ—μ„œ thread1의 μš°μ„ μˆœμœ„λ₯Ό 졜고 μš°μ„ μˆœμœ„λ‘œ μ„€μ •ν•˜κ³ , thread2의 μš°μ„ μˆœμœ„λ₯Ό μ΅œμ € μš°μ„ μˆœμœ„λ‘œ μ„€μ •ν•˜μ˜€μŠ΅λ‹ˆλ‹€. 그리고 두 μŠ€λ ˆλ“œλ₯Ό μ‹œμž‘ν•˜λ©΄, thread1은 thread2보닀 더 λ§Žμ€ CPU μžμ›μ„ 할당받을 ν™•λ₯ μ΄ λ†’μ•„μ§‘λ‹ˆλ‹€.

동기화

μ—¬λŸ¬ μŠ€λ ˆλ“œκ°€ 곡유 데이터에 λ™μ‹œμ— μ ‘κ·Όν•˜μ—¬ μˆ˜μ •ν•˜λŠ” 경우, μŠ€λ ˆλ“œ κ°„μ˜ 데이터 일관성 λ¬Έμ œκ°€ λ°œμƒν•  수 μžˆμŠ΅λ‹ˆλ‹€. 이λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄ μžλ°”μ—μ„œλŠ” 동기화(synchronization) κΈ°λŠ₯을 μ œκ³΅ν•©λ‹ˆλ‹€. 동기화λ₯Ό μ‚¬μš©ν•˜μ—¬ ν•œ μŠ€λ ˆλ“œκ°€ 곡유 데이터λ₯Ό μ‚¬μš©ν•˜λŠ” λ™μ•ˆ λ‹€λ₯Έ μŠ€λ ˆλ“œμ˜ 접근을 μ œν•œν•  수 μžˆμŠ΅λ‹ˆλ‹€.

public class Counter {
    private int count;

    public synchronized void increment() {
        count++;
    }

    public int getCount() {
        return count;
    }
}

μœ„μ˜ μ˜ˆμ œμ—μ„œ increment λ©”μ„œλ“œλŠ” synchronized ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ λ™κΈ°ν™”λœ λ©”μ„œλ“œλ‘œ μ •μ˜λ˜μ—ˆμŠ΅λ‹ˆλ‹€. 이둜써 ν•œ μŠ€λ ˆλ“œκ°€ increment λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜μ—¬ countλ₯Ό μ¦κ°€μ‹œν‚€λŠ” λ™μ•ˆ λ‹€λ₯Έ μŠ€λ ˆλ“œλŠ” 접근을 μ œν•œν•˜κ²Œ λ©λ‹ˆλ‹€.

μœ„μ™€ 같은 λ°©λ²•μœΌλ‘œ μžλ°”μ—μ„œ μŠ€λ ˆλ“œλ₯Ό 생성, μ œμ–΄ν•˜κ³  λ™κΈ°ν™”ν•˜λŠ” 방법을 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. μŠ€λ ˆλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ 병렬성을 ν™œμš©ν•  λ•Œμ—λŠ” 동기화 λ¬Έμ œμ™€ 데이터 일관성을 κ³ λ €ν•˜μ—¬ μ μ ˆν•œ 방법을 μ„ νƒν•˜μ—¬ μ‚¬μš©ν•΄μ•Ό ν•©λ‹ˆλ‹€.

3. μŠ€λ ˆλ“œ μ‘°μž‘ (Manipulating Threads)

μžλ°”μ—μ„œλŠ” μŠ€λ ˆλ“œλ₯Ό μ‘°μž‘ν•˜μ—¬ μŠ€λ ˆλ“œμ˜ λ™μž‘μ„ μ œμ–΄ν•˜κ³  λͺ¨λ‹ˆν„°λ§ν•  수 μžˆλŠ” λ‹€μ–‘ν•œ κΈ°λŠ₯을 μ œκ³΅ν•©λ‹ˆλ‹€. 이λ₯Ό 톡해 μŠ€λ ˆλ“œμ˜ 싀행을 μΌμ‹œ 정지, 재개, 쀑지 등을 ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μŠ€λ ˆλ“œ μΌμ‹œ 정지

μŠ€λ ˆλ“œλ₯Ό μΌμ‹œ μ •μ§€μ‹œν‚€λŠ” λ°©λ²•μœΌλ‘œλŠ” sleep() λ©”μ„œλ“œμ™€ yield() λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

sleep()

sleep() λ©”μ„œλ“œλŠ” ν˜„μž¬ μ‹€ν–‰ 쀑인 μŠ€λ ˆλ“œλ₯Ό μ§€μ •λœ μ‹œκ°„ λ™μ•ˆ λ©ˆμΆ”λŠ”λ° μ‚¬μš©λ©λ‹ˆλ‹€. μ΄λŠ” 주어진 μ‹œκ°„μ΄ κ²½κ³Όν•˜κ±°λ‚˜ interrupt() λ©”μ„œλ“œκ°€ 호좜되면 λ‹€μ‹œ μ‹€ν–‰λ˜κΈ° μ‹œμž‘ν•©λ‹ˆλ‹€.

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

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

μœ„μ˜ μ˜ˆμ œμ—μ„œ run() λ©”μ„œλ“œ λ‚΄λΆ€μ—μ„œ Thread.sleep(1000)을 ν˜ΈμΆœν•˜μ—¬ μŠ€λ ˆλ“œλ₯Ό 1초 λ™μ•ˆ λ©ˆμΆ”λ„λ‘ ν•©λ‹ˆλ‹€. 이둜써 μŠ€λ ˆλ“œκ°€ μ‹€ν–‰λ˜λ©΄ 1λΆ€ν„° 5κΉŒμ§€ 숫자λ₯Ό 좜λ ₯ν•˜κ³ , 1μ΄ˆλ§ˆλ‹€ μˆ«μžκ°€ 좜λ ₯되게 λ©λ‹ˆλ‹€.

yield()

yield() λ©”μ„œλ“œλŠ” ν˜„μž¬ μ‹€ν–‰ 쀑인 μŠ€λ ˆλ“œλ₯Ό μΌμ‹œμ μœΌλ‘œ λ©ˆμΆ”κ³  λ‹€λ₯Έ μŠ€λ ˆλ“œμ—κ²Œ μ‹€ν–‰ 기회λ₯Ό μ–‘λ³΄ν•©λ‹ˆλ‹€. μ΄λ•Œ μ–΄λ–€ μŠ€λ ˆλ“œμ—κ²Œ μ‹€ν–‰ 기회λ₯Ό 양보할지 μ •ν™•νžˆ κ²°μ •ν•  수 μ—†μŠ΅λ‹ˆλ‹€.

public class YieldThread extends Thread {
    public void run() {
        for (int i = 1; i <= 5; i++) {
            System.out.println("Thread: " + i);
            Thread.yield();
        }
    }

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

μœ„μ˜ μ˜ˆμ œμ—μ„œ run() λ©”μ„œλ“œ λ‚΄λΆ€μ—μ„œ Thread.yield()λ₯Ό ν˜ΈμΆœν•˜μ—¬ μŠ€λ ˆλ“œλ₯Ό μΌμ‹œ μ •μ§€μ‹œν‚€λ„λ‘ ν•©λ‹ˆλ‹€. 이둜써 μŠ€λ ˆλ“œκ°€ μ‹€ν–‰λ˜λ©΄ 1λΆ€ν„° 5κΉŒμ§€ 숫자λ₯Ό 좜λ ₯ν•˜κ³ , 각 숫자 좜λ ₯ 이후에 μΌμ‹œμ μœΌλ‘œ λ©ˆμΆ”κ³  λ‹€λ₯Έ μŠ€λ ˆλ“œμ—κ²Œ μ‹€ν–‰ 기회λ₯Ό μ–‘λ³΄ν•©λ‹ˆλ‹€.

μŠ€λ ˆλ“œ 쀑지

μŠ€λ ˆλ“œλ₯Ό μ€‘μ§€μ‹œν‚€λŠ” λ°©λ²•μœΌλ‘œλŠ” stop() λ©”μ„œλ“œμ™€ interrupt() λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ stop() λ©”μ„œλ“œλŠ” μ‚¬μš©μ„ ꢌμž₯ν•˜μ§€ μ•ŠμœΌλ©°, λŒ€μ‹  interrupt() λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

stop()

stop() λ©”μ„œλ“œλŠ” μŠ€λ ˆλ“œλ₯Ό κ°•μ œλ‘œ μ€‘μ§€μ‹œν‚€λŠ”λ° μ‚¬μš©λ©λ‹ˆλ‹€. ν•˜μ§€λ§Œ 이 λ©”μ„œλ“œλŠ” μŠ€λ ˆλ“œκ°€ μ‹€ν–‰ 쀑인 μƒνƒœμ—μ„œ λ°”λ‘œ μ€‘μ§€λ˜κΈ° λ•Œλ¬Έμ—, μŠ€λ ˆλ“œκ°€ μ •λ¦¬ν•˜μ§€ λͺ»ν•œ μž‘μ—…μ΄λ‚˜ λΈ”λ‘λœ λ¦¬μ†ŒμŠ€ 등을 남길 수 μžˆμŠ΅λ‹ˆλ‹€. κ·Έλž˜μ„œ stop() λ©”μ„œλ“œλŠ” μ‚¬μš©μ„ ꢌμž₯ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

interrupt()

interrupt() λ©”μ„œλ“œλŠ” μŠ€λ ˆλ“œμ˜ interrupted μƒνƒœλ₯Ό μ„€μ •ν•˜μ—¬ μŠ€λ ˆλ“œκ°€ μ’…λ£Œλ  수 μžˆλ„λ‘ ν•©λ‹ˆλ‹€. 호좜된 μŠ€λ ˆλ“œλŠ” InterruptedException을 λ˜μ§„ ν›„ μ’…λ£Œν•  수 μžˆμŠ΅λ‹ˆλ‹€.

public class InterruptThread extends Thread {
    public void run() {
        try {
            for (int i = 1; i <= 5; i++) {
                System.out.println("Thread: " + i);
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            System.out.println("Thread Interrupted");
        }
    }

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

        try {
            Thread.sleep(3000);
            thread.interrupt();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

μœ„μ˜ μ˜ˆμ œμ—μ„œ run() λ©”μ„œλ“œ λ‚΄λΆ€μ—μ„œ Thread.sleep(1000)을 ν˜ΈμΆœν•˜μ—¬ μŠ€λ ˆλ“œλ₯Ό 1초 λ™μ•ˆ λ©ˆμΆ”λ„λ‘ ν•©λ‹ˆλ‹€. main λ©”μ„œλ“œμ—μ„œλŠ” 3초 후에 thread μŠ€λ ˆλ“œλ₯Ό interrupt() λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜μ—¬ μ€‘μ§€μ‹œν‚€λ„λ‘ ν•©λ‹ˆλ‹€. 이후 run λ©”μ„œλ“œμ—μ„œ Thread.sleep(1000) μ‹€ν–‰ 쀑에 InterruptedException이 λ°œμƒν•˜λ©΄, μŠ€λ ˆλ“œκ°€ μ’…λ£Œλ˜λ„λ‘ μ²˜λ¦¬ν•©λ‹ˆλ‹€.

μŠ€λ ˆλ“œ μƒνƒœ

μŠ€λ ˆλ“œμ˜ μƒνƒœλŠ” Thread 클래슀의 getState() λ©”μ„œλ“œλ₯Ό 톡해 μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€. μŠ€λ ˆλ“œ μƒνƒœλŠ” NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED λ“±μœΌλ‘œ μ •μ˜λ˜λ©°, 각각의 μƒνƒœλŠ” λ‹€μŒκ³Ό 같은 의미λ₯Ό κ°€μ§‘λ‹ˆλ‹€.

  • NEW: μŠ€λ ˆλ“œκ°€ 아직 μ‹œμž‘λ˜μ§€ μ•Šμ€ μƒνƒœλ₯Ό μ˜λ―Έν•©λ‹ˆλ‹€.
  • RUNNABLE: μŠ€λ ˆλ“œκ°€ μ‹€ν–‰ 쀑인 μƒνƒœλ₯Ό μ˜λ―Έν•©λ‹ˆλ‹€.
  • BLOCKED: μŠ€λ ˆλ“œκ°€ 곡유 λ¦¬μ†ŒμŠ€λ₯Ό μ‚¬μš©ν•˜λ €κ³  ν•˜μ§€λ§Œ λ‹€λ₯Έ μŠ€λ ˆλ“œμ— μ˜ν•΄ μ μœ λ˜μ—ˆκΈ° λ•Œλ¬Έμ— 싀행이 λΆˆκ°€λŠ₯ν•œ μƒνƒœλ₯Ό μ˜λ―Έν•©λ‹ˆλ‹€.
  • WAITING: μŠ€λ ˆλ“œκ°€ λ‹€λ₯Έ μŠ€λ ˆλ“œμ—μ„œ 톡지λ₯Ό κΈ°λ‹€λ¦¬λ©΄μ„œ 싀행을 멈좘 μƒνƒœλ₯Ό

    4. 닀쀑 μŠ€λ ˆλ“œ ν™˜κ²½μ—μ„œμ˜ 동기화 (Synchronization)

닀쀑 μŠ€λ ˆλ“œ ν™˜κ²½μ—μ„œλŠ” μ—¬λŸ¬ μŠ€λ ˆλ“œκ°€ 곡유 데이터에 λ™μ‹œμ— μ ‘κ·Όν•˜μ—¬ μˆ˜μ •ν•˜λŠ” κ²½μš°κ°€ λ°œμƒν•  수 μžˆμŠ΅λ‹ˆλ‹€. μ΄λŸ¬ν•œ μƒν™©μ—μ„œ μŠ€λ ˆλ“œ κ°„μ˜ 데이터 일관성을 μœ μ§€ν•˜κΈ° μœ„ν•΄ μžλ°”μ—μ„œλŠ” 동기화(Synchronization) κΈ°λŠ₯을 μ œκ³΅ν•©λ‹ˆλ‹€. λ™κΈ°ν™”λŠ” ν•œ μŠ€λ ˆλ“œκ°€ 곡유 데이터λ₯Ό μ‚¬μš©ν•˜λŠ” λ™μ•ˆ λ‹€λ₯Έ μŠ€λ ˆλ“œμ˜ 접근을 μ œν•œν•˜μ—¬ 데이터 일관성을 보μž₯ν•˜λŠ” κΈ°λ²•μž…λ‹ˆλ‹€.

synchronized ν‚€μ›Œλ“œ

μžλ°”μ—μ„œ 동기화λ₯Ό κ΅¬ν˜„ν•˜λŠ” κ°€μž₯ κ°„λ‹¨ν•œ 방법은 synchronized ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. synchronized ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜λ©΄ λ©”μ„œλ“œ λ˜λŠ” 블둝을 μž„κ³„ μ˜μ—­(critical section) 으둜 지정할 수 μžˆμŠ΅λ‹ˆλ‹€. μž„κ³„ μ˜μ—­μ€ ν•œ λ²ˆμ— ν•œ μŠ€λ ˆλ“œλ§Œ μ‹€ν–‰ν•  수 μžˆλŠ” μ˜μ—­μž…λ‹ˆλ‹€.

λ©”μ„œλ“œ 동기화

public class Counter {
    private int count;

    public synchronized void increment() {
        count++;
    }

    public synchronized int getCount() {
        return count;
    }
}

μœ„μ˜ μ˜ˆμ œμ—μ„œ increment() λ©”μ„œλ“œμ™€ getCount() λ©”μ„œλ“œλŠ” synchronized ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ λ™κΈ°ν™”λœ λ©”μ„œλ“œλ‘œ μ •μ˜λ˜μ—ˆμŠ΅λ‹ˆλ‹€. 이둜써 ν•œ μŠ€λ ˆλ“œκ°€ increment() λ˜λŠ” getCount() λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜μ—¬ count 값을 λ³€κ²½ν•˜κ±°λ‚˜ μ½λŠ” λ™μ•ˆ λ‹€λ₯Έ μŠ€λ ˆλ“œλŠ” 접근을 μ œν•œλ°›κ²Œ λ©λ‹ˆλ‹€.

블둝 동기화

public class Counter {
    private int count;

    public void increment() {
        synchronized (this) {
            count++;
        }
    }

    public int getCount() {
        synchronized (this) {
            return count;
        }
    }
}

μœ„μ˜ μ˜ˆμ œμ—μ„œ increment() λ©”μ„œλ“œμ™€ getCount() λ©”μ„œλ“œλŠ” synchronized λΈ”λ‘μœΌλ‘œ μ •μ˜λ˜μ—ˆμŠ΅λ‹ˆλ‹€. synchronized (this)λ₯Ό μ‚¬μš©ν•˜μ—¬ μž„κ³„ μ˜μ—­μ„ μ§€μ •ν•©λ‹ˆλ‹€. 이둜써 ν•œ μŠ€λ ˆλ“œκ°€ 블둝 λ‚΄μ˜ μ½”λ“œλ₯Ό μ‹€ν–‰ν•˜λŠ” λ™μ•ˆ λ‹€λ₯Έ μŠ€λ ˆλ“œλŠ” 접근을 μ œν•œλ°›μŠ΅λ‹ˆλ‹€.

잠금(Locks)과 쑰건(Conditions)

μžλ°”μ—μ„œλŠ” Lock μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ‚¬μš©ν•˜μ—¬ 더 μœ μ—°ν•œ 동기화λ₯Ό μ œκ³΅ν•©λ‹ˆλ‹€. Lock μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ‚¬μš©ν•˜λ©΄ 더 λ‹€μ–‘ν•œ 잠금 및 쑰건을 μ‚¬μš©ν•˜μ—¬ μŠ€λ ˆλ“œ 동기화λ₯Ό μ‘°μž‘ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Counter {
    private int count;
    private Lock lock;

    public Counter() {
        count = 0;
        lock = new ReentrantLock();
    }

    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }

    public int getCount() {
        lock.lock();
        try {
            return count;
        } finally {
            lock.unlock();
        }
    }
}

μœ„μ˜ μ˜ˆμ œμ—μ„œλŠ” Lock μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•œ ReentrantLock 클래슀λ₯Ό μ‚¬μš©ν•˜μ—¬ 잠금

5. μžλ°” μŠ€λ ˆλ“œ 예제

μŠ€λ ˆλ“œ 생성 예제

public class MyThread extends Thread {
    public void run() {
        System.out.println("Hello from MyThread!");
    }

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

μœ„μ˜ μ˜ˆμ œλŠ” MyThread 클래슀λ₯Ό μ •μ˜ν•˜κ³  run() λ©”μ„œλ“œλ₯Ό μ˜€λ²„λΌμ΄λ“œν•˜μ—¬ μŠ€λ ˆλ“œμ˜ μ‹€ν–‰ λ‘œμ§μ„ μž‘μ„±ν•œ μ˜ˆμ œμž…λ‹ˆλ‹€. main λ©”μ„œλ“œμ—μ„œ MyThread 객체λ₯Ό μƒμ„±ν•˜κ³  start() λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜μ—¬ μŠ€λ ˆλ“œλ₯Ό μ‹€ν–‰μ‹œν‚΅λ‹ˆλ‹€. start() λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄ μƒˆλ‘œμš΄ μŠ€λ ˆλ“œκ°€ μ‹œμž‘λ˜κ³ , run() λ©”μ„œλ“œκ°€ μ‹€ν–‰λ©λ‹ˆλ‹€.

μŠ€λ ˆλ“œ 동기화 예제

public class Counter {
    private int count;

    public synchronized void increment() {
        count++;
    }

    public synchronized int getCount() {
        return count;
    }
}

public class SynchronizedThread extends Thread {
    private Counter counter;

    public SynchronizedThread(Counter counter) {
        this.counter = counter;
    }

    public void run() {
        for (int i = 0; i < 5; i++) {
            counter.increment();
        }
    }

    public static void main(String[] args) {
        Counter counter = new Counter();

        SynchronizedThread thread1 = new SynchronizedThread(counter);
        SynchronizedThread thread2 = new SynchronizedThread(counter);

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

        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Count: " + counter.getCount());
    }
}

μœ„μ˜ μ˜ˆμ œλŠ” λ™κΈ°ν™”λœ μΉ΄μš΄ν„°λ₯Ό μ‚¬μš©ν•˜λŠ” 두 개의 μŠ€λ ˆλ“œλ₯Ό μƒμ„±ν•˜λŠ” μ˜ˆμ œμž…λ‹ˆλ‹€. Counter ν΄λž˜μŠ€λŠ” synchronized ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ λ™κΈ°ν™”λœ λ©”μ„œλ“œμΈ increment()κ³Ό getCount()λ₯Ό 가지고 μžˆμŠ΅λ‹ˆλ‹€. SynchronizedThread ν΄λž˜μŠ€λŠ” Counter 객체λ₯Ό μƒμ„±μžλ‘œ λ°›μ•„μ„œ increment() λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜μ—¬ μΉ΄μš΄ν„° 값을 μ¦κ°€μ‹œν‚΅λ‹ˆλ‹€.

main λ©”μ„œλ“œμ—μ„œλŠ” Counter 객체λ₯Ό μƒμ„±ν•˜κ³  두 개의 SynchronizedThread 객체λ₯Ό μƒμ„±ν•˜μ—¬ μΉ΄μš΄ν„°λ₯Ό μ¦κ°€μ‹œν‚΅λ‹ˆλ‹€. μŠ€λ ˆλ“œ 싀행이 λͺ¨λ‘ λλ‚œ ν›„μ—λŠ” μΉ΄μš΄ν„°μ˜ μ΅œμ’… 값을 좜λ ₯ν•©λ‹ˆλ‹€.

μŠ€λ ˆλ“œ μΌμ‹œ 정지 예제

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

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

μœ„μ˜ μ˜ˆμ œλŠ” μΌμ •ν•œ κ°„κ²©μœΌλ‘œ 숫자λ₯Ό 좜λ ₯ν•˜λŠ” μŠ€λ ˆλ“œμž…λ‹ˆλ‹€. run() λ©”μ„œλ“œμ—μ„œλŠ” 1λΆ€ν„° 5κΉŒμ§€μ˜ 숫자λ₯Ό 좜λ ₯ν•˜κ³ , Thread.sleep(1000)을 ν˜ΈμΆœν•˜μ—¬ 1초 λ™μ•ˆ μŠ€λ ˆλ“œλ₯Ό μΌμ‹œ μ •μ§€μ‹œν‚΅λ‹ˆλ‹€. 이둜써 각 숫자 좜λ ₯ ν›„ 1초의 μΌμ‹œ 정지가 λ°œμƒν•˜κ²Œ λ©λ‹ˆλ‹€.

μŠ€λ ˆλ“œ 쀑지 예제

public class InterruptThread extends Thread {
    public void run() {
        try {
            for (int i = 1; i <= 5; i++) {
                System.out.println("Thread: " + i);
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            System.out.println("Thread Interrupted");
        }
    }

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

        try {
            Thread.sleep(3000);
            thread.interrupt();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

μœ„μ˜ μ˜ˆμ œλŠ” interrupt() λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ μŠ€λ ˆλ“œλ₯Ό μ€‘μ§€μ‹œν‚€λŠ” μ˜ˆμ œμž…λ‹ˆλ‹€. run() λ©”μ„œλ“œμ—μ„œλŠ” 1λΆ€ν„° 5κΉŒμ§€μ˜ 숫자λ₯Ό 좜λ ₯ν•˜κ³ , Thread.sleep(1000)을 ν˜ΈμΆœν•˜μ—¬ 1초 λ™μ•ˆ μŠ€λ ˆλ“œλ₯Ό μΌμ‹œ μ •μ§€μ‹œν‚΅λ‹ˆλ‹€. main λ©”μ„œλ“œμ—μ„œλŠ” 3초 후에 thread μŠ€λ ˆλ“œλ₯Ό interrupt() λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜μ—¬ μ€‘μ§€μ‹œν‚΅λ‹ˆλ‹€. 이후 run λ©”μ„œλ“œμ—μ„œ Thread.sleep(1000) μ‹€ν–‰ 쀑에 InterruptedException이 λ°œμƒν•˜λ©΄, "Thread Interrupted"λΌλŠ” λ©”μ‹œμ§€λ₯Ό 좜λ ₯ν•©λ‹ˆλ‹€.

5. μžλ°” μŠ€λ ˆλ“œ 예제

μŠ€λ ˆλ“œ 생성 예제

public class MyThread extends Thread {
    public void run() {
        System.out.println("Hello from MyThread!");
    }

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

μœ„μ˜ μ˜ˆμ œλŠ” MyThread 클래슀λ₯Ό μ •μ˜ν•˜κ³  run() λ©”μ„œλ“œλ₯Ό μ˜€λ²„λΌμ΄λ“œν•˜μ—¬ μŠ€λ ˆλ“œμ˜ μ‹€ν–‰ λ‘œμ§μ„ μž‘μ„±ν•œ μ˜ˆμ œμž…λ‹ˆλ‹€. main λ©”μ„œλ“œμ—μ„œ MyThread 객체λ₯Ό μƒμ„±ν•˜κ³  start() λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜μ—¬ μŠ€λ ˆλ“œλ₯Ό μ‹€ν–‰μ‹œν‚΅λ‹ˆλ‹€. start() λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄ μƒˆλ‘œμš΄ μŠ€λ ˆλ“œκ°€ μ‹œμž‘λ˜κ³ , run() λ©”μ„œλ“œκ°€ μ‹€ν–‰λ©λ‹ˆλ‹€.

이 μ˜ˆμ œμ—μ„œλŠ” MyThread ν΄λž˜μŠ€κ°€ Thread 클래슀λ₯Ό 상속받아 μŠ€λ ˆλ“œλ‘œ λ™μž‘ν•˜λ„λ‘ κ΅¬ν˜„λ˜μ—ˆμŠ΅λ‹ˆλ‹€. Thread ν΄λž˜μŠ€μ—λŠ” 기본적으둜 run() λ©”μ„œλ“œκ°€ 있고, 이 λ©”μ„œλ“œλ₯Ό μ˜€λ²„λΌμ΄λ“œν•˜μ—¬ μŠ€λ ˆλ“œμ˜ λ™μž‘μ„ ꡬ체적으둜 μ •μ˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μŠ€λ ˆλ“œ 동기화 예제

public class Counter {
    private int count;

    public synchronized void increment() {
        count++;
    }

    public synchronized int getCount() {
        return count;
    }
}

public class SynchronizedThread extends Thread {
    private Counter counter;

    public SynchronizedThread(Counter counter) {
        this.counter = counter;
    }

    public void run() {
        for (int i = 0; i < 5; i++) {
            counter.increment();
        }
    }

    public static void main(String[] args) {
        Counter counter = new Counter();

        SynchronizedThread thread1 = new SynchronizedThread(counter);
        SynchronizedThread thread2 = new SynchronizedThread(counter);

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

        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Count: " + counter.getCount());
    }
}

μœ„μ˜ μ˜ˆμ œλŠ” λ™κΈ°ν™”λœ μΉ΄μš΄ν„°λ₯Ό μ‚¬μš©ν•˜λŠ” 두 개의 μŠ€λ ˆλ“œλ₯Ό μƒμ„±ν•˜λŠ” μ˜ˆμ œμž…λ‹ˆλ‹€. Counter ν΄λž˜μŠ€μ—λŠ” synchronized ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ λ™κΈ°ν™”λœ λ©”μ„œλ“œμΈ increment()κ³Ό getCount()λ₯Ό μž‘μ„±ν–ˆμŠ΅λ‹ˆλ‹€. SynchronizedThread ν΄λž˜μŠ€λŠ” Counter 객체λ₯Ό μƒμ„±μžλ‘œ λ°›μ•„μ„œ increment() λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜μ—¬ μΉ΄μš΄ν„° 값을 μ¦κ°€μ‹œν‚΅λ‹ˆλ‹€.

main λ©”μ„œλ“œμ—μ„œλŠ” Counter 객체λ₯Ό μƒμ„±ν•˜κ³  두 개의 SynchronizedThread 객체λ₯Ό μƒμ„±ν•˜μ—¬ μΉ΄μš΄ν„°λ₯Ό μ¦κ°€μ‹œν‚΅λ‹ˆλ‹€. μŠ€λ ˆλ“œμ˜ 싀행이 λͺ¨λ‘ λλ‚œ ν›„μ—λŠ” μΉ΄μš΄ν„°μ˜ μ΅œμ’… 값을 좜λ ₯ν•©λ‹ˆλ‹€.synchronized ν‚€μ›Œλ“œλ‘œ λ©”μ„œλ“œλ₯Ό λ™κΈ°ν™”ν•¨μœΌλ‘œμ¨ ν•œ μŠ€λ ˆλ“œκ°€ ν•΄λ‹Ή λ©”μ„œλ“œλ₯Ό μ‹€ν–‰ν•˜λŠ” λ™μ•ˆ λ‹€λ₯Έ μŠ€λ ˆλ“œμ˜ 접근을 μ œν•œν•˜κ²Œ λ©λ‹ˆλ‹€. 이λ₯Ό 톡해 곡유 데이터에 λŒ€ν•œ μŠ€λ ˆλ“œ κ°„μ˜ 일관성을 μœ μ§€ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μŠ€λ ˆλ“œ μΌμ‹œ 정지 예제

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

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

μœ„μ˜ μ˜ˆμ œλŠ” sleep() λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ μŠ€λ ˆλ“œλ₯Ό μΌμ‹œ μ •μ§€μ‹œν‚€λŠ” μ˜ˆμ œμž…λ‹ˆλ‹€. run() λ©”μ„œλ“œμ—μ„œλŠ” 1λΆ€ν„° 5κΉŒμ§€μ˜ 숫자λ₯Ό 좜λ ₯ν•˜κ³ , Thread.sleep(1000)을 ν˜ΈμΆœν•˜μ—¬ 1초 λ™μ•ˆ μŠ€λ ˆλ“œλ₯Ό μΌμ‹œ μ •μ§€μ‹œν‚΅λ‹ˆλ‹€. μ΄λ ‡κ²Œ ν•˜λ©΄ 각 숫자 좜λ ₯ ν›„ 1μ΄ˆμ”© μΌμ‹œ 정지가 λ°œμƒν•˜κ²Œ λ©λ‹ˆλ‹€.

sleep() λ©”μ„œλ“œλŠ” μ§€μ •λœ μ‹œκ°„ λ™μ•ˆ μŠ€λ ˆλ“œλ₯Ό μΌμ‹œ μ •μ§€μ‹œν‚€λŠ” 역할을 ν•©λ‹ˆλ‹€. Thread.sleep(1000)은 1000λ°€λ¦¬μ΄ˆ(1초) λ™μ•ˆ μŠ€λ ˆλ“œλ₯Ό μΌμ‹œ μ •μ§€μ‹œν‚¨ ν›„ λ‹€μŒ μ½”λ“œλ₯Ό μ‹€ν–‰ν•©λ‹ˆλ‹€. InterruptedException이 λ°œμƒν•  수 μžˆμœΌλ―€λ‘œ μ˜ˆμ™Έ 처리λ₯Ό ν•΄μ£Όμ–΄μ•Ό ν•©λ‹ˆλ‹€.

μŠ€λ ˆλ“œ 쀑지 예제

public class InterruptThread extends Thread {
    public void run() {
        try {
            for (int i = 1; i <= 5; i++) {
                System.out.println("Thread: " + i);
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            System.out.println("Thread Interrupted");
        }
    }

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

        try {
            Thread.sleep(3000);
            thread.interrupt();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

μœ„μ˜ μ˜ˆμ œλŠ” interrupt() λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ μŠ€λ ˆλ“œλ₯Ό μ€‘μ§€μ‹œν‚€λŠ” μ˜ˆμ œμž…λ‹ˆλ‹€. run() λ©”μ„œλ“œμ—μ„œλŠ” 1λΆ€ν„° 5κΉŒμ§€μ˜ 숫자λ₯Ό 좜λ ₯ν•˜κ³ , Thread.sleep(1000)을 ν˜ΈμΆœν•˜μ—¬ 1초 λ™μ•ˆ μŠ€λ ˆλ“œλ₯Ό μΌμ‹œ μ •μ§€μ‹œν‚΅λ‹ˆλ‹€. main λ©”μ„œλ“œμ—μ„œλŠ” 3초 후에 thread μŠ€λ ˆλ“œλ₯Ό interrupt() λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜μ—¬ μ€‘μ§€μ‹œν‚΅λ‹ˆλ‹€.

interrupt() λ©”μ„œλ“œλŠ” ν•΄λ‹Ή μŠ€λ ˆλ“œλ₯Ό μ€‘μ§€μ‹œν‚€λŠ” 역할을 ν•©λ‹ˆλ‹€. μ˜ˆμ œμ—μ„œλŠ” thread.interrupt()λ₯Ό ν˜ΈμΆœν•˜μ—¬ thread μŠ€λ ˆλ“œλ₯Ό μ€‘μ§€μ‹œν‚΅λ‹ˆλ‹€. run λ©”μ„œλ“œμ—μ„œ Thread.sleep(1000) μ‹€ν–‰ 쀑에 InterruptedException이 λ°œμƒν•˜λ©΄, catch 블둝이 μ‹€ν–‰λ˜κ³  "Thread Interrupted"λΌλŠ” λ©”μ‹œμ§€κ°€ 좜λ ₯λ©λ‹ˆλ‹€.

5. μžλ°” μŠ€λ ˆλ“œ 예제

μŠ€λ ˆλ“œ 생성 예제

public class MyThread extends Thread {
    public void run() {
        System.out.println("Hello from MyThread!");
    }

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

이 μ˜ˆμ œμ—μ„œλŠ” MyThread 클래슀λ₯Ό μ •μ˜ν•˜κ³  run() λ©”μ„œλ“œλ₯Ό μ˜€λ²„λΌμ΄λ”©ν•˜μ—¬ μŠ€λ ˆλ“œμ˜ μ‹€ν–‰ λ‘œμ§μ„ μž‘μ„±ν–ˆμŠ΅λ‹ˆλ‹€. main λ©”μ„œλ“œμ—μ„œλŠ” MyThread 객체λ₯Ό μƒμ„±ν•˜κ³  start() λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜μ—¬ μŠ€λ ˆλ“œλ₯Ό μ‹€ν–‰μ‹œμΌ°μŠ΅λ‹ˆλ‹€. start() λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄ μƒˆλ‘œμš΄ μŠ€λ ˆλ“œκ°€ μ‹œμž‘λ˜κ³ , ν•΄λ‹Ή μŠ€λ ˆλ“œμ˜ run() λ©”μ„œλ“œκ°€ μ‹€ν–‰λ©λ‹ˆλ‹€.

이 μ˜ˆμ œμ—μ„œ MyThread ν΄λž˜μŠ€λŠ” Thread 클래슀λ₯Ό 상속받아 μŠ€λ ˆλ“œλ‘œ λ™μž‘ν•˜λ„λ‘ κ΅¬ν˜„λ˜μ—ˆμŠ΅λ‹ˆλ‹€. Thread ν΄λž˜μŠ€λŠ” 기본적으둜 run() λ©”μ„œλ“œλ₯Ό 가지며, 이 λ©”μ„œλ“œλ₯Ό μ˜€λ²„λΌμ΄λ”©ν•˜μ—¬ μŠ€λ ˆλ“œκ°€ λ™μž‘ν•  λ‚΄μš©μ„ ꡬ체적으둜 μ •μ˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μŠ€λ ˆλ“œ 동기화 예제

public class Counter {
    private int count;

    public synchronized void increment() {
        count++;
    }

    public synchronized int getCount() {
        return count;
    }
}

public class SynchronizedThread extends Thread {
    private Counter counter;

    public SynchronizedThread(Counter counter) {
        this.counter = counter;
    }

    public void run() {
        for (int i = 0; i < 5; i++) {
            counter.increment();
        }
    }

    public static void main(String[] args) {
        Counter counter = new Counter();

        SynchronizedThread thread1 = new SynchronizedThread(counter);
        SynchronizedThread thread2 = new SynchronizedThread(counter);

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

        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Count: " + counter.getCount());
    }
}

μœ„μ˜ μ˜ˆμ œλŠ” λ™κΈ°ν™”λœ μΉ΄μš΄ν„°λ₯Ό μ‚¬μš©ν•˜λŠ” 두 개의 μŠ€λ ˆλ“œλ₯Ό μƒμ„±ν•˜λŠ” μ˜ˆμ œμž…λ‹ˆλ‹€. Counter ν΄λž˜μŠ€λŠ” synchronized ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ λ™κΈ°ν™”λœ increment()κ³Ό getCount() λ©”μ„œλ“œλ₯Ό 가지고 μžˆμŠ΅λ‹ˆλ‹€. SynchronizedThread ν΄λž˜μŠ€λŠ” Counter 객체λ₯Ό μƒμ„±μžλ‘œ λ°›μ•„μ„œ increment() λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜μ—¬ μΉ΄μš΄ν„° 값을 μ¦κ°€μ‹œν‚΅λ‹ˆλ‹€.

main λ©”μ„œλ“œμ—μ„œλŠ” Counter 객체λ₯Ό μƒμ„±ν•˜κ³  두 개의 SynchronizedThread 객체λ₯Ό μƒμ„±ν•˜μ—¬ μΉ΄μš΄ν„°λ₯Ό μ¦κ°€μ‹œν‚΅λ‹ˆλ‹€. μŠ€λ ˆλ“œμ˜ 싀행이 λͺ¨λ‘ λλ‚œ ν›„μ—λŠ” μΉ΄μš΄ν„°μ˜ μ΅œμ’… 값을 좜λ ₯ν•©λ‹ˆλ‹€. synchronized ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ λ©”μ„œλ“œλ₯Ό λ™κΈ°ν™”ν•˜λ©΄ ν•œ μŠ€λ ˆλ“œκ°€ ν•΄λ‹Ή λ©”μ„œλ“œλ₯Ό μ‹€ν–‰ν•˜λŠ” λ™μ•ˆ λ‹€λ₯Έ μŠ€λ ˆλ“œμ˜ 접근을 μ œν•œν•  수 μžˆμŠ΅λ‹ˆλ‹€. 이λ₯Ό 톡해 곡유 데이터에 λŒ€ν•œ μŠ€λ ˆλ“œ κ°„μ˜ 일관성을 μœ μ§€ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μŠ€λ ˆλ“œ μΌμ‹œ 정지 예제

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

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

μœ„μ˜ μ˜ˆμ œλŠ” sleep() λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ μŠ€λ ˆλ“œλ₯Ό μΌμ‹œ μ •μ§€μ‹œν‚€λŠ” μ˜ˆμ œμž…λ‹ˆλ‹€. run() λ©”μ„œλ“œμ—μ„œλŠ” 1λΆ€ν„° 5κΉŒμ§€μ˜ 숫자λ₯Ό 좜λ ₯ν•˜κ³ , Thread.sleep(1000)을 ν˜ΈμΆœν•˜μ—¬ 1초 λ™μ•ˆ μŠ€λ ˆλ“œλ₯Ό μΌμ‹œ μ •μ§€μ‹œν‚΅λ‹ˆλ‹€. μ΄λ ‡κ²Œ ν•˜λ©΄ 각 숫자 좜λ ₯ ν›„ 1μ΄ˆμ”© μΌμ‹œ 정지가 λ°œμƒν•˜κ²Œ λ©λ‹ˆλ‹€.

sleep() λ©”μ„œλ“œλŠ” μ§€μ •λœ μ‹œκ°„ λ™μ•ˆ μŠ€λ ˆλ“œλ₯Ό μΌμ‹œ μ •μ§€μ‹œν‚€λŠ” 역할을 ν•©λ‹ˆλ‹€. Thread.sleep(1000)은 1000λ°€λ¦¬μ΄ˆ(1초) λ™μ•ˆ μŠ€λ ˆλ“œλ₯Ό μΌμ‹œ μ •μ§€μ‹œν‚¨ ν›„ λ‹€μŒ μ½”λ“œλ₯Ό μ‹€ν–‰ν•©λ‹ˆλ‹€. InterruptedException이 λ°œμƒν•  수 μžˆμœΌλ―€λ‘œ μ˜ˆμ™Έ 처리λ₯Ό ν•΄μ£Όμ–΄μ•Ό ν•©λ‹ˆλ‹€.

μŠ€λ ˆλ“œ 쀑지 예제

public class InterruptThread extends Thread {
    public void run() {
        try {
            for (int i = 1; i

λŒ“κΈ€