1. Thread란?
프로세스 안에서 실질적으로 작업을 실행하는 단위
프로세스에는 적어도 한 개 이상의 Thread가 있다.
main Thread 하나에서 Thread를 추가 생성하게 되면 멀티 Thread  환경이 된다.
2. Thread의 생성자
1) Thread
- Thread() : 새로운 스레드 객체 할당
- Thread(String name) : 새로운 스레드 객체가 할당되며, 스레드 이름은 name으로 설정됨
- Thread(Runnable target) : Runnable target이 구현된 스레드 객체 할당
- Thread(Runnable target, String name) : Runnable target이 구현된 스레드 객체가 할당되면 스레드 이름은 name으로 설정됨
3. Thread를 사용하면 좋은 상황 👍
- 동시에 해야할 때
- I/O가 일어날 때
4. Thread 생성 방법
- Thread 클래스를 상속 받는 방법
- Runnable 인터페이스를 구현하는 방법
5. Thread 기본 1
package ex19;
// 스레드 기본 (스레드 객체 생성, 스레드 시작, 타겟(run메소드) 만들기)
public class Th01 {
    public static void sub1() {
        for (int i = 1; i <= 5; i++) {
            System.out.println("스레드 1 : " + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
    public static void sub2() {
        for (int i = 1; i <= 5; i++) {
            System.out.println("스레드 2 : " + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
    //   class SSS implements Runnable {
    //       public void run() {
    //       }
    //   }
    public static void main(String[] args) { // cpu -> 메인 쓰레드
        Thread t1 = new Thread(() -> sub1()); // 한 줄이면 중괄호 생략 가능, run메소드 = (() -> sub1()), 타겟은 run
        t1.start();
        new Thread(() -> sub2() // 타겟은 run
        ).start();
    }
}

6. Thread 기본 2
package ex19;
public class Th02 {
    static String product = null;
    public static void main(String[] args) {
        Thread supp = new Thread(() -> {
            try {
                Thread.sleep(10000);
                product = "바나나깡";
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        supp.start();
        Thread lis = new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(500);
                    if (product != null) {
                        System.out.println("상품이 입고되었습니다. : " + product);
                        break;
                    }
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        lis.start();
    }
}7. Thread 동시 작업 처리 예제
package ex19;
class MyFile {
    public void write() {
        try {
            Thread.sleep(5000);
            System.out.println("파일 쓰기 완료");
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}
class 화가 {
    public void 그림그리기() {
        System.out.println("그림 그리기 완료");
    }
}
// 화가
public class Th03 {
    public static void main(String[] args) {
        MyFile myFile = new MyFile();
        화가 painter = new 화가();
        painter.그림그리기();
        new Thread(() -> {
            myFile.write();
        }).start();
        painter.그림그리기();
    }
}
8. Class로 Thread 만들기
package ex19;
import java.util.ArrayList;
import java.util.List;
// 1. 상속받고 2. 타겟 재정의
class MyThread extends Thread {
    private List<Integer> list;
    @Override
    public void run() { // 타겟 재정의
        for (int i = 0; i < 10; i++) {
            System.out.println("MyThread : " + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
    public MyThread(List<Integer> list) {
        this.list = list;
    }
    public void addList(int num) {
        list.add(num);
    }
    public List<Integer> getList() {
        return list;
    }
}
// 클래스로 스레드 만들기 (스레드별 상태 보관)
public class Th04 {
    public static void main(String[] args) {
        MyThread t1 = new MyThread(new ArrayList<>()); // MyThread는 ArrayList에 의존한다.
        t1.start();
    }
}
9. Thread 숫자 카운터 프로그램 예제
package ex19;
import javax.swing.*;
public class Th05 extends JFrame { // JFrame = 자바에서 그림그리는 도구
    private boolean state = true;
    private int count = 0;
    private int count2 = 0;
    private JLabel countLabel;
    private JLabel count2Label;
    public Th05() {
        setTitle("숫자 카운터 프로그램");
        setVisible(true);
        setSize(300, 200);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        // 레이아웃 매니저 설정
        setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
        // 숫자를 표시할 레이블 생성
        countLabel = new JLabel("숫자1: " + count);
        count2Label = new JLabel("숫자2: " + count2);
        countLabel.setAlignmentX(CENTER_ALIGNMENT);
        count2Label.setAlignmentX(CENTER_ALIGNMENT);
        add(countLabel);
        add(count2Label);
        // 멈춤 버튼 생성
        JButton increaseButton = new JButton("멈춤");
        increaseButton.setAlignmentX(CENTER_ALIGNMENT);
        add(increaseButton);
        // 버튼에 액션 리스너 추가
        increaseButton.addActionListener(e -> {
            state = false;
        });
        new Thread(() -> {
            while (state) {
                try {
                    Thread.sleep(1000);
                    count++;
                    countLabel.setText("숫자1 : " + count);
                } catch (InterruptedException ex) {
                    throw new RuntimeException(ex);
                }
            }
        }).start();
        new Thread(() -> {
            while (state) {
                try {
                    Thread.sleep(1000);
                    count2++;
                    count2Label.setText("숫자2 : " + count2);
                } catch (InterruptedException ex) {
                    throw new RuntimeException(ex);
                }
            }
        }).start();
    }
    public static void main(String[] args) {
        new Th05();
    }
}10. Thread가 return해야 할 때 (첫번째 방법)
package ex19;
//콜백
class Store implements Runnable {
    int qty;
    @Override
    public void run() {
        // 통신 -> 다운로드
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        qty = 5;
    }
}
/*
스레드에서 받은 데이터를 리턴 받아서 응용하고 싶을때!!
1. 타이밍 맞추기 (임시방편 - 그래도 쓰는 사람 많음)
2. 리스너 (부하가 너무 큼)
3. 콜백 (제일 좋음)
 */
// 사용 이유 : 동시에 해야할 때, I/O가 일어날 때!!
public class Th06 {
    public static void main(String[] args) {
        int totalQty = 10;
        Store store = new Store();
        Thread t1 = new Thread(store);
        t1.start();
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("재고수량 :" + (store.qty + totalQty));
    }
}
11. Thread가 return해야 할 때 (두번째 방법)
package ex19;
//콜백
class Store implements Runnable {
    Integer qty;
    @Override
    public void run() {
        // 통신 -> 다운로드
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        qty = 5;
    }
}
/*
스레드에서 받은 데이터를 리턴 받아서 응용하고 싶을때!!
1. 타이밍 맞추기 (임시방편 - 그래도 쓰는 사람 많음)
2. 리스너 (부하가 너무 큼)
3. 콜백 (제일 좋음)
 */
// 사용 이유 : 동시에 해야할 때, I/O가 일어날 때!!
public class Th06 {
    public static void main(String[] args) {
        int totalQty = 10;
        Store store = new Store();
        Thread t1 = new Thread(store);
        t1.start();
        while (true) {
            if (store.qty != null) break;
            try {
                Thread.sleep(10);
                System.out.println(store.qty + "지켜본다");
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        System.out.println("재고수량 :" + (store.qty + totalQty));
    }
}

12. Thread 콜백 메소드 활용
package ex19;
//콜백
// [1] 콜백 메소드 만들기
interface Callback {
    void 입고(int qty); // 괄호 안에는 리턴 받고 싶은 인수를 만들어주면 된다. = 정확하게는 파라미터
}
class Store implements Runnable {
    // [2] 리턴이 필요한 곳으로 가서 콜백 메소드 전달 받기
    Integer qty;
    Callback callback;
    public Store(Callback callback) {
        this.callback = callback;
    }
    @Override
    public void run() {
        // 통신 -> 다운로드
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        qty = 5;
        callback.입고(qty); // [3] 종료시 콜백 메소드 호출
    }
}
/*
스레드에서 받은 데이터를 리턴 받아서 응용하고 싶을때!!
1. 타이밍 맞추기 (임시방편 - 그래도 쓰는 사람 많음)
2. 리스너 (부하가 너무 큼)
3. 콜백 (제일 좋음)
 */
// 사용 이유 : 동시에 해야할 때, I/O가 일어날 때!!
public class Th06 {
    public static void main(String[] args) {
        int totalQty = 10;
        Store store = new Store(qty -> {
            System.out.println("재고수량 :" + (qty + totalQty));
        });
        Thread t1 = new Thread(store);
        t1.start();
    }
}

Share article